def write_zipped(self, filepath):
        """Write the GTFS feed in the given file."""
        with zipfile.ZipFile(filepath, mode='w', compression=zipfile.ZIP_DEFLATED) as zfile:
            for name, buffer in self._buffers.items():
                encoded_values = io.BytesIO(buffer.getvalue().encode('utf-8'))
                zfile.writestr('{}.txt'.format(name),
                               encoded_values.getbuffer())
            for name, path in self._files.items():
                zfile.write(path, arcname=name)

def write_zipped ( self , filepath ) : with zipfile . ZipFile ( filepath , mode = 'w' , compression = zipfile . ZIP_DEFLATED ) as zfile : for name , buffer in self . _buffers . items ( ) : encoded_values = io . BytesIO ( buffer . getvalue ( ) . encode ( 'utf-8' ) ) zfile . writestr ( '{}.txt' . format ( name ) , encoded_values . getbuffer ( ) ) for name , path in self . _files . items ( ) : zfile . write ( path , arcname = name )


def write_unzipped(self, destination):
        """Write GTFS text files in the given path."""
        for name, buffer in self._buffers.items():
            with open(os.path.join(destination,
                                   '{}.txt'.format(name)),
                      'w', encoding='utf-8') as file:
                file.write(buffer.getvalue())
        for name, path in self._files.items():
            shutil.copy(path, os.path.join(destination, name))

def write_unzipped ( self , destination ) : for name , buffer in self . _buffers . items ( ) : with open ( os . path . join ( destination , '{}.txt' . format ( name ) ) , 'w' , encoding = 'utf-8' ) as file : file . write ( buffer . getvalue ( ) ) for name , path in self . _files . items ( ) : shutil . copy ( path , os . path . join ( destination , name ) )

Write GTFS text files in the given path .


def build_agency(relation, nodes):
    """Extract agency information."""
    # TODO: find out the operator for routes without operator tag.
    # See: http://wiki.openstreetmap.org/wiki/Key:operator
    # Quote from the above link:
    #
    #    If the vast majority of a certain object in an area is operated by a certain
    #    organization and only very few by others then it may be sufficient to only tag the
    #    exceptions. For example, when nearly all roads in an area are managed by a local
    #    authority then it would be sufficient to only tag those that are not with an operator
    #    tag.
    op = relation.tags.get('operator')
    agency_url = relation.tags.get('url') or relation.tags.get('contact_website')

    if not op:
        return

    agency_id = int(hashlib.sha256(op.encode('utf8')).hexdigest(), 16) % 10**8

    return Agency(agency_id, agency_url, op, '')


def extract_stops(relation, nodes, visited_stop_ids, stop_to_station_map):
    """Extract stops in a relation."""
    # member_role: stop, halt, platform, terminal, etc.
    for member_type, member_id, member_role in relation.member_info:

        if member_id not in visited_stop_ids and \
            member_id in nodes and\
                member_role in ('stop', 'halt'):

            location_type = ''

            visited_stop_ids.add(member_id)
            yield Stop(
                member_id,
                nodes[member_id].tags.get('name') or
                "Unnamed {} stop.".format(relation.tags.get('route')),
                nodes[member_id].lon if member_id in nodes else '',
                nodes[member_id].lat if member_id in nodes else '',
                relation.id,
                _map_wheelchair(nodes[member_id].tags.get('wheelchair')),
                location_type,
                stop_to_station_map.get(member_id, ''))


def build_shape(relation, nodes, ways):
    """Extract shape of one route."""
    sequence_index = 0

    for member_type, member_id, member_role in relation.member_info:

        if member_id in nodes:
            yield Shape(
                relation.id,
                nodes[member_id].lat,
                nodes[member_id].lon,
                sequence_index)

            sequence_index += 1

        # Do we need to consider ways too? It dramatically increases the number of shapes.
        elif member_id in ways:
            continue
        #     for point in ways[member_id].points:
        #         shape = Shape(
        #             relation.id,
        #             point.lat,
        #             point.lon,
        #             sequence_index)
        #         sequence_index += 1

        else:
            # Ignore excessive logging for now.
            pass

#     for point in ways[member_id].points:


def get_supported_versions(self):
        """
        Gets a list of supported U2F versions from the device.
        """
        if not hasattr(self, '_versions'):
            try:
                self._versions = [self.send_apdu(INS_GET_VERSION).decode()]
            except exc.APDUError as e:
                # v0 didn't support the instruction.
                self._versions = ['v0'] if e.code == 0x6d00 else []

        return self._versions

def
get_supported_versions
(
self
)
:
if
not
hasattr
(
self
,
'_versions'
)
:
try
:
self
.
_versions
=
[
self
.
send_apdu
(
INS_GET_VERSION
)
.
decode
(
)
]
except
exc
.
APDUError
as
e
:
# v0 didn't support the instruction.
self
.
_versions
=
[
'v0'
]
if
e
.
code
==
0x6d00
else
[
]
return
self
.
_versions

Gets a list of supported U2F versions from the device .


def send_apdu(self, ins, p1=0, p2=0, data=b''):
        """
        Sends an APDU to the device, and waits for a response.
        """
        if data is None:
            data = b''
        elif isinstance(data, int):
            data = int2byte(data)

        size = len(data)
        l0 = size >> 16 & 0xff
        l1 = size >> 8 & 0xff
        l2 = size & 0xff
        apdu_data = struct.pack('B B B B B B B %is B B' % size,
                                0, ins, p1, p2, l0, l1, l2, data, 0x00, 0x00)
        try:
            resp = self._do_send_apdu(apdu_data)
        except Exception as e:
            # TODO Use six.reraise if/when Six becomes an agreed dependency.
            raise exc.DeviceError(e)
        status = struct.unpack('>H', resp[-2:])[0]
        data = resp[:-2]
        if status != APDU_OK:
            raise exc.APDUError(status)
        return data

Sends an APDU to the device and waits for a response .


def authenticate(devices, params, facet, check_only):
    """
    Interactively authenticates a AuthenticateRequest using an attached U2F
    device.
    """
    for device in devices[:]:
        try:
            device.open()
        except:
            devices.remove(device)

    try:
        prompted = False
        while devices:
            removed = []
            for device in devices:
                try:
                    return u2f.authenticate(device, params, facet, check_only)
                except exc.APDUError as e:
                    if e.code == APDU_USE_NOT_SATISFIED:
                        if check_only:
                            sys.stderr.write('\nCorrect U2F device present!\n')
                            sys.exit(0)
                        if not prompted:
                            sys.stderr.write('\nTouch the flashing U2F device '
                                             'to authenticate...\n')
                            prompted = True
                    else:
                        removed.append(device)
                except exc.DeviceError:
                    removed.append(device)
            devices = [d for d in devices if d not in removed]
            for d in removed:
                d.close()
            time.sleep(0.25)
    finally:
        for device in devices:
            device.close()
    sys.stderr.write('\nThe required U2F device is not present!\n')
    sys.exit(1)

Interactively authenticates a AuthenticateRequest using an attached U2F device .


def register(device, data, facet):
    """
    Register a U2F device

    data = {
        "version": "U2F_V2",
        "challenge": string, //b64 encoded challenge
        "appId": string, //app_id
    }

    """

    if isinstance(data, string_types):
        data = json.loads(data)

    if data['version'] != VERSION:
        raise ValueError('Unsupported U2F version: %s' % data['version'])

    app_id = data.get('appId', facet)
    verify_facet(app_id, facet)
    app_param = sha256(app_id.encode('utf8')).digest()

    client_data = {
        'typ': 'navigator.id.finishEnrollment',
        'challenge': data['challenge'],
        'origin': facet
    }
    client_data = json.dumps(client_data)
    client_param = sha256(client_data.encode('utf8')).digest()

    request = client_param + app_param

    p1 = 0x03
    p2 = 0
    response = device.send_apdu(INS_ENROLL, p1, p2, request)

    return {
        'registrationData': websafe_encode(response),
        'clientData': websafe_encode(client_data)
    }

def
register
(
device
,
data
,
facet
)
:
if
isinstance
(
data
,
string_types
)
:
data
=
json
.
loads
(
data
)
if
data
[
'version'
]
!=
VERSION
:
raise
ValueError
(
'Unsupported U2F version: %s'
%
data
[
'version'
]
)
app_id
=
data
.
get
(
'appId'
,
facet
)
verify_facet
(
app_id
,
facet
)
app_param
=
sha256
(
app_id
.
encode
(
'utf8'
)
)
.
digest
(
)
client_data
=
{
'typ'
:
'navigator.id.finishEnrollment'
,
'challenge'
:
data
[
'challenge'
]
,
'origin'
:
facet
}
client_data
=
json
.
dumps
(
client_data
)
client_param
=
sha256
(
client_data
.
encode
(
'utf8'
)
)
.
digest
(
)
request
=
client_param
+
app_param
p1
=
0x03
p2
=
0
response
=
device
.
send_apdu
(
INS_ENROLL
,
p1
,
p2
,
request
)
return
{
'registrationData'
:
websafe_encode
(
response
)
,
'clientData'
:
websafe_encode
(
client_data
)
}


def authenticate(device, data, facet, check_only=False):
    """
    Signs an authentication challenge

    data = {
        'version': "U2F_V2",
        'challenge': websafe_encode(self.challenge),
        'appId': self.binding.app_id,
        'keyHandle': websafe_encode(self.binding.key_handle)
    }

    """

    if isinstance(data, string_types):
        data = json.loads(data)

    if data['version'] != VERSION:
        raise ValueError('Unsupported U2F version: %s' % data['version'])

    app_id = data.get('appId', facet)
    verify_facet(app_id, facet)
    app_param = sha256(app_id.encode('utf8')).digest()

    key_handle = websafe_decode(data['keyHandle'])

    # Client data
    client_data = {
        'typ': 'navigator.id.getAssertion',
        'challenge': data['challenge'],
        'origin': facet
    }
    client_data = json.dumps(client_data)
    client_param = sha256(client_data.encode('utf8')).digest()

    request = client_param + app_param + int2byte(
        len(key_handle)) + key_handle

    p1 = 0x07 if check_only else 0x03
    p2 = 0
    response = device.send_apdu(INS_SIGN, p1, p2, request)

    return {
        'clientData': websafe_encode(client_data),
        'signatureData': websafe_encode(response),
        'keyHandle': data['keyHandle']
    }

def
authenticate
(
device
,
data
,
facet
,
check_only
=
False
)
:
if
isinstance
(
data
,
string_types
)
:
data
=
json
.
loads
(
data
)
if
data
[
'version'
]
!=
VERSION
:
raise
ValueError
(
'Unsupported U2F version: %s'
%
data
[
'version'
]
)
app_id
=
data
.
get
(
'appId'
,
facet
)
verify_facet
(
app_id
,
facet
)
app_param
=
sha256
(
app_id
.
encode
(
'utf8'
)
)
.
digest
(
)
key_handle
=
websafe_decode
(
data
[
'keyHandle'
]
)
# Client data
client_data
=
{
'typ'
:
'navigator.id.getAssertion'
,
'challenge'
:
data
[
'challenge'
]
,
'origin'
:
facet
}
client_data
=
json
.
dumps
(
client_data
)
client_param
=
sha256
(
client_data
.
encode
(
'utf8'
)
)
.
digest
(
)
request
=
client_param
+
app_param
+
int2byte
(
len
(
key_handle
)
)
+
key_handle
p1
=
0x07
if
check_only
else
0x03
p2
=
0
response
=
device
.
send_apdu
(
INS_SIGN
,
p1
,
p2
,
request
)
return
{
'clientData'
:
websafe_encode
(
client_data
)
,
'signatureData'
:
websafe_encode
(
response
)
,
'keyHandle'
:
data
[
'keyHandle'
]
}


def register(devices, params, facet):
    """
    Interactively registers a single U2F device, given the RegistrationRequest.
    """
    for device in devices[:]:
        try:
            device.open()
        except:
            devices.remove(device)

    sys.stderr.write('\nTouch the U2F device you wish to register...\n')
    try:
        while devices:
            removed = []
            for device in devices:
                try:
                    return u2f.register(device, params, facet)
                except exc.APDUError as e:
                    if e.code == APDU_USE_NOT_SATISFIED:
                        pass
                    else:
                        removed.append(device)
                except exc.DeviceError:
                    removed.append(device)
            devices = [d for d in devices if d not in removed]
            for d in removed:
                d.close()
            time.sleep(0.25)
    finally:
        for device in devices:
            device.close()
    sys.stderr.write('\nUnable to register with any U2F device.\n')
    sys.exit(1)

Interactively registers a single U2F device given the RegistrationRequest .


def u2str(data):
    """Recursively converts unicode objects to UTF-8 encoded byte strings."""
    if isinstance(data, dict):
        return {u2str(k): u2str(v) for k, v in data.items()}
    elif isinstance(data, list):
        return [u2str(x) for x in data]
    elif isinstance(data, text_type):
        return data.encode('utf-8')
    else:
        return data

def u2str ( data ) : if isinstance ( data , dict ) : return { u2str ( k ) : u2str ( v ) for k , v in data . items ( ) } elif isinstance ( data , list ) : return [ u2str ( x ) for x in data ] elif isinstance ( data , text_type ) : return data . encode ( 'utf-8' ) else : return data

Recursively converts unicode objects to UTF - 8 encoded byte strings .


def wrap_function(func=None, error_threshold=None, reraise_exception=True, save_current_stack_trace=True):
    ''' Wraps a function with reporting to errors backend '''
    # This if/else allows wrap_function to behave like a normal decorator when
    # used like:
    #         @wrap_function
    #         def some_func():
    #
    # However, it also allows wrap_function to also be passed keyword arguments
    # like the following:
    #         @wrap_function(error_threshold=3, reraise_exception=False)
    #         def some_func():
    if func:
        return flawless.client.client._wrap_function_with_error_decorator(
            func=func,
            error_threshold=error_threshold,
            reraise_exception=reraise_exception,
            save_current_stack_trace=save_current_stack_trace)
    else:
        return functools.partial(flawless.client.client._wrap_function_with_error_decorator,
                                 error_threshold=error_threshold,
                                 reraise_exception=reraise_exception,
                                 save_current_stack_trace=save_current_stack_trace)


def wrap_class(cls, error_threshold=None):
    ''' Wraps a class with reporting to errors backend by decorating each function of the class.
            Decorators are injected under the classmethod decorator if they exist.
    '''
    methods = inspect.getmembers(cls, inspect.ismethod) + inspect.getmembers(cls, inspect.isfunction)
    for method_name, method in methods:
        wrapped_method = flawless.client.client._wrap_function_with_error_decorator(
            method if not im_self(method) else im_func(method),
            save_current_stack_trace=False,
            error_threshold=error_threshold,
        )
        if im_self(method):
            wrapped_method = classmethod(wrapped_method)
        setattr(cls, method_name, wrapped_method)
    return cls

def wrap_class ( cls , error_threshold = None ) : methods = inspect . getmembers ( cls , inspect . ismethod ) + inspect . getmembers ( cls , inspect . isfunction ) for method_name , method in methods : wrapped_method = flawless . client . client . _wrap_function_with_error_decorator ( method if not im_self ( method ) else im_func ( method ) , save_current_stack_trace = False , error_threshold = error_threshold , ) if im_self ( method ) : wrapped_method = classmethod ( wrapped_method ) setattr ( cls , method_name , wrapped_method ) return cls

Wraps a class with reporting to errors backend by decorating each function of the class . Decorators are injected under the classmethod decorator if they exist .


def _matches_filepath_pattern(self, filepath):
        '''Given a filepath, and a list of regex patterns, this function returns true
        if filepath matches any one of those patterns'''
        if not self.only_blame_patterns:
            return True

        for pattern in self.only_blame_patterns:
            if pattern.match(filepath):
                return True
        return False

def _matches_filepath_pattern ( self , filepath ) : if not self . only_blame_patterns : return True for pattern in self . only_blame_patterns : if pattern . match ( filepath ) : return True return False

Given a filepath and a list of regex patterns this function returns true if filepath matches any one of those patterns


def _get_email(self, email):
        '''Given an email address, check the email_remapping table to see if the email
        should be sent to a different address. This function also handles overriding
        the email domain if ignore_vcs_email_domain is set or the domain was missing'''
        if not email or "@" not in email:
            return None

        if email in self.email_remapping.remap:
            return self.email_remapping.remap[email]
        prefix, domain = email.split("@", 2)
        if prefix in self.email_remapping.remap:
            return self.email_remapping.remap[prefix]
        if "." not in domain or config.ignore_vcs_email_domain:
            return "%s@%s" % (prefix, config.email_domain_name)
        return email

def _get_email ( self , email ) : if not email or "@" not in email : return None if email in self . email_remapping . remap : return self . email_remapping . remap [ email ] prefix , domain = email . split ( "@" , 2 ) if prefix in self . email_remapping . remap : return self . email_remapping . remap [ prefix ] if "." not in domain or config . ignore_vcs_email_domain : return "%s@%s" % ( prefix , config . email_domain_name ) return email

Given an email address check the email_remapping table to see if the email should be sent to a different address . This function also handles overriding the email domain if ignore_vcs_email_domain is set or the domain was missing


def _get_entry(self, entry, entry_tree):
        '''Helper function for retrieving a particular entry from the prefix trees'''
        for e in entry_tree[entry.filename]:
            if entry == e:
                return e

def _get_entry ( self , entry , entry_tree ) : for e in entry_tree [ entry . filename ] : if entry == e : return e


def markdown_to_reST(text):
    '''This is not a general purpose converter. Only converts this readme'''
    # Convert parameters to italics and prepend a newline
    text = re.sub(pattern=r"\n       (\w+) - (.+)\n",
                  repl=r"\n\n       *\g<1>* - \g<2>\n",
                  string=text)

    # Parse [http://url](text), and just leave the url
    text = re.sub(pattern=r"\[([^\]]+)\]\([^)]+\)",
                  repl=r"\g<1>",
                  string=text)

    # Disable formatting of numbered lists
    text = re.sub(pattern=r"\n(\d+). ",
                  repl=r"\n\\\g<1>. ",
                  string=text)
    return text

This is not a general purpose converter . Only converts this readme


def serve(conf_path, storage_factory=None):
    """This method starts the server. There are two processes, one is an HTTP server that shows
    and admin interface and the second is a Thrift server that the client code calls.

    Arguments:
        `conf_path` - The path to your flawless.cfg file
        `storage_factory` - You can pass in your own storage class that implements StorageInterface. You must implement
                            storage_cls if you want Flawless to be horizontally scalable, since by default it will just
                            store everything on the local disk.
    """

    flawless.lib.config.init_config(conf_path)
    # Try and create datadir if it doesn't exist. For instance it might be in /tmp
    if not os.path.exists(config.data_dir_path):
        os.makedirs(config.data_dir_path)

    storage_factory = storage_factory or (lambda partition: DiskStorage(partition=partition))

    # Setup root logger
    root_logger = logging.getLogger()
    root_handler = logging.handlers.TimedRotatingFileHandler(
        filename=config.log_file, when='d', interval=1, backupCount=config.log_days_to_keep)
    root_logger.setLevel(getattr(logging, config.log_level))
    root_logger.addHandler(root_handler)

    child_pid = os.fork()
    if child_pid == 0:
        # Setup HTTP server
        handler = FlawlessWebServiceHandler(storage_factory=storage_factory)
        server = SimpleThreadedHTTPServer(('', config.http_port), SimpleRequestHTTPHandler)
        server.attach_service(handler)
        server.request_queue_size = 50

        try:
            server.serve_forever()
        except (KeyboardInterrupt, SystemExit):
            server.server_close()
    else:
        # Setup Thrift server
        handler = FlawlessThriftServiceHandler(storage_factory=storage_factory)
        processor = Flawless.Processor(handler)
        transport = TSocket.TServerSocket(port=config.port)
        tfactory = TTransport.TFramedTransportFactory()
        pfactory = TBinaryProtocol.TBinaryProtocolFactory()
        server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
        try:
            server.serve()
        except (KeyboardInterrupt, SystemExit):
            handler.errors_seen.sync()
            transport.close()
            os.kill(child_pid, signal.SIGINT)

This method starts the server . There are two processes one is an HTTP server that shows and admin interface and the second is a Thrift server that the client code calls .


def record_error(hostname, exc_info, preceding_stack=None, error_threshold=None, additional_info=None):
    ''' Helper function to record errors to the flawless backend '''
    stack = []
    exc_type, exc_value, sys_traceback = exc_info

    while sys_traceback is not None:
        stack.append(sys_traceback)
        sys_traceback = sys_traceback.tb_next

    stack_lines = []
    for row in preceding_stack or []:
        stack_lines.append(
            api_ttypes.StackLine(filename=os.path.abspath(row[0]), line_number=row[1],
                                 function_name=row[2], text=row[3])
        )

    for index, tb in enumerate(stack):
        filename = tb.tb_frame.f_code.co_filename
        func_name = tb.tb_frame.f_code.co_name
        lineno = tb.tb_lineno
        line = linecache.getline(filename, lineno, tb.tb_frame.f_globals)
        frame_locals = None
        if index >= (len(stack) - NUM_FRAMES_TO_SAVE):
            # Include some limits on max string length & number of variables to keep things from getting
            # out of hand
            frame_locals = dict((k, _myrepr(k, v)) for k, v in
                                list(tb.tb_frame.f_locals.items())[:MAX_LOCALS] if k != "self")
            if "self" in tb.tb_frame.f_locals and hasattr(tb.tb_frame.f_locals["self"], "__dict__"):
                frame_locals.update(dict(("self." + k, _myrepr(k, v)) for k, v in
                                         list(tb.tb_frame.f_locals["self"].__dict__.items())[:MAX_LOCALS]
                                         if k != "self"))

        stack_lines.append(
            api_ttypes.StackLine(filename=os.path.abspath(filename), line_number=lineno,
                                 function_name=func_name, text=line, frame_locals=frame_locals)
        )

    # Check LRU cache & potentially do not send error report if this client has already reported this error
    # several times.
    key = CachedErrorInfo.get_hash_key(stack_lines)
    info = ERROR_CACHE.get(key) or CachedErrorInfo()
    info.increment()
    ERROR_CACHE[key] = info
    if info.should_report():
        error_count = info.mark_reported()
        _send_request(
            api_ttypes.RecordErrorRequest(
                traceback=stack_lines,
                exception_message=repr(exc_value),
                exception_type=exc_type.__module__ + "." + exc_type.__name__,
                hostname=hostname,
                error_threshold=error_threshold,
                additional_info=additional_info,
                error_count=error_count,
            )
        )


def url_to_image(url):
    """
    Fetch an image from url and convert it into a Pillow Image object
    """
    r = requests.get(url)
    image = StringIO(r.content)
    return image

def url_to_image ( url ) : r = requests . get ( url ) image = StringIO ( r . content ) return image


def string_to_image(image_string):
    """
    Convert string datas into a Pillow Image object
    """
    image_filelike = StringIO(image_string)
    image = Image.open(image_filelike)
    return image

def string_to_image ( image_string ) : image_filelike = StringIO ( image_string ) image = Image . open ( image_filelike ) return image


def validate(validator):
    """
    Return a decorator that validates arguments with provided `validator`
    function.

    This will also store the validator function as `func.validate`.
    The decorator returned by this function, can bypass the validator
    if `validate=False` is passed as argument otherwise the fucntion is
    called directly.

    The validator must raise an exception, if the function can not
    be called.
    """

    def decorator(func):
        """Bound decorator to a particular validator function"""

        @wraps(func)
        def wrapper(image, size, validate=True):
            if validate:
                validator(image, size)
            return func(image, size)
        return wrapper

    return decorator

Return a decorator that validates arguments with provided validator function .


def _is_big_enough(image, size):
    """Check that the image's size superior to `size`"""
    if (size[0] > image.size[0]) and (size[1] > image.size[1]):
        raise ImageSizeError(image.size, size)

def _is_big_enough ( image , size ) : if ( size [ 0 ] > image . size [ 0 ] ) and ( size [ 1 ] > image . size [ 1 ] ) : raise ImageSizeError ( image . size , size )

Check that the image s size superior to size


def _width_is_big_enough(image, width):
    """Check that the image width is superior to `width`"""
    if width > image.size[0]:
        raise ImageSizeError(image.size[0], width)

def _width_is_big_enough ( image , width ) : if width > image . size [ 0 ] : raise ImageSizeError ( image . size [ 0 ] , width )

Check that the image width is superior to width


def _height_is_big_enough(image, height):
    """Check that the image height is superior to `height`"""
    if height > image.size[1]:
        raise ImageSizeError(image.size[1], height)

def _height_is_big_enough ( image , height ) : if height > image . size [ 1 ] : raise ImageSizeError ( image . size [ 1 ] , height )

Check that the image height is superior to height


def parse_category(self, item, field_name, source_name):
        """
        Converts the text category to a tasks.Category instance.
        """
        # Get and checks for the corresponding slug
        slug = category_map.get(self.get_value(item, source_name), None)
        if not slug:
            return None
        # Load the category instance
        try:
            return Category.objects.get(slug=slug)
        except Category.DoesNotExist:
            pass

Converts the text category to a tasks . Category instance .


def parse_totals(self, item, field_name, source_name):
        """
        Parse numeric fields.
        """
        val = self.get_value(item, source_name)
        try:
            return int(val)
        except:
            return 0

def parse_totals ( self , item , field_name , source_name ) : val = self . get_value ( item , source_name ) try : return int ( val ) except : return 0


def get_items(self):
        """
        Iterator of the list of items in the XML source.
        """
        # Use `iterparse`, it's more efficient, specially for big files
        for event, item in ElementTree.iterparse(self.source):
            if item.tag == self.item_tag_name:
                yield item
                # Releases the item from memory
                item.clear()

Iterator of the list of items in the XML source .


def save_error(self, data, exception_info):
        """
        Saves an error in the error list.
        """
        # TODO: what to do with errors? Let it flow? Write to a log file?
        self.errors.append({'data': data,
                            'exception': ''.join(format_exception(*exception_info)),
                            })


def parse(self):
        """
        Parses all data from the source, saving model instances.
        """
        # Checks if the source is loaded
        if not self.loaded:
            self.load(self.source)

        for item in self.get_items():
            # Parse the fields from the source into a dict
            data = self.parse_item(item)
            # Get the instance from the DB, or a new one
            instance = self.get_instance(data)
            # Feed instance with data
            self.feed_instance(data, instance)
            # Try to save the instance or keep the error
            try:
                self.save_item(item, data, instance)
            except Exception as e:
                self.save_error(data, sys.exc_info())

        # Unload the source
        self.unload()

Parses all data from the source saving model instances .


def parse_item(self, item):
        """
        Receives an item and returns a dictionary of field values.
        """
        # Create a dictionary from values for each field
        parsed_data = {}

        for field_name in self.fields:
            # A field-name may be mapped to another identifier on the source,
            # it could be a XML path or a CSV column name / position.
            # Defaults to the field-name itself.
            source_name = self.field_map.get(field_name, field_name)

            # Uses a custom method "parse_%(field_name)"
            # or get the value from the item
            parse = getattr(self, 'parse_%s' % field_name, None)
            if parse:
                value = parse(item, field_name, source_name)
            else:
                value = self.get_value(item, source_name)

            # Add the value to the parsed data
            parsed_data[field_name] = value
        return parsed_data

Receives an item and returns a dictionary of field values .


def get_instance(self, data):
        """
        Get an item from the database or an empty one if not found.
        """
        # Get unique fields
        unique_fields = self.unique_fields

        # If there are no unique fields option, all items are new
        if not unique_fields:
            return self.model()

        # Build the filter
        filter = dict([(f, data[f]) for f in unique_fields])

        # Get the instance from the DB or use a new instance
        try:
            instance = self.model._default_manager.get(**filter)
        except self.model.DoesNotExist:
            return self.model()

        return instance

Get an item from the database or an empty one if not found .


def save_item(self, item, data, instance, commit=True):
        """
        Saves a model instance to the database.
        """
        if commit:
            instance.save()
        return instance

def save_item ( self , item , data , instance , commit = True ) : if commit : instance . save ( ) return instance

Saves a model instance to the database .


def download_file(url, dest):
    """
    Downloads a HTTP resource from `url` and save to `dest`.

    Capable of dealing with Gzip compressed content.
    """

    # Create the HTTP request
    request = urllib2.Request(url)

    # Add the header to accept gzip encoding
    request.add_header('Accept-encoding', 'gzip')

    # Open the request
    opener = urllib2.build_opener()
    response = opener.open(request)

    # Retrieve data
    data = response.read()

    # If the data is compressed, put the data in a stream and decompress
    if response.headers.get('content-encoding', '') == 'gzip':
        stream = StringIO.StringIO(data)
        gzipper = gzip.GzipFile(fileobj=stream)
        data = gzipper.read()

    # Write to a file
    f = open(dest, 'wb')
    f.write(data)
    f.close()

Downloads a HTTP resource from url and save to dest . Capable of dealing with Gzip compressed content .


def load(self, source):
        """
        Opens the source file.
        """
        self.source = open(self.source, 'rb')
        self.loaded = True

def load ( self , source ) : self . source = open ( self . source , 'rb' ) self . loaded = True


def get_items(self):
        """
        Iterator to read the rows of the CSV file.
        """
        # Get the csv reader
        reader = csv.reader(self.source)
        # Get the headers from the first line
        headers = reader.next()
        # Read each line yielding a dictionary mapping
        # the column headers to the row values
        for row in reader:
            # Skip empty rows
            if not row:
                continue
            yield dict(zip(headers, row))

Iterator to read the rows of the CSV file .


def allow_network_access(self, value: bool):
        """
        Raises ValueError if this sandbox instance is currently running.
        """
        if self._is_running:
            raise ValueError(
                "Cannot change network access settings on a running sandbox")

        self._allow_network_access = value

Raises ValueError if this sandbox instance is currently running .


def run_command(self,
                    args: List[str],
                    max_num_processes: int=None,
                    max_stack_size: int=None,
                    max_virtual_memory: int=None,
                    as_root: bool=False,
                    stdin: FileIO=None,
                    timeout: int=None,
                    check: bool=False,
                    truncate_stdout: int=None,
                    truncate_stderr: int=None) -> 'CompletedCommand':
        """
        Runs a command inside the sandbox and returns the results.

        :param args: A list of strings that specify which command should
            be run inside the sandbox.

        :param max_num_processes: The maximum number of processes the
            command is allowed to spawn.

        :param max_stack_size: The maximum stack size, in bytes, allowed
            for the command.

        :param max_virtual_memory: The maximum amount of memory, in
            bytes, allowed for the command.

        :param as_root: Whether to run the command as a root user.

        :param stdin: A file object to be redirected as input to the
            command's stdin. If this is None, /dev/null is sent to the
            command's stdin.

        :param timeout: The time limit for the command.

        :param check: Causes CalledProcessError to be raised if the
            command exits nonzero or times out.

        :param truncate_stdout: When not None, stdout from the command
            will be truncated after this many bytes.

        :param truncate_stderr: When not None, stderr from the command
            will be truncated after this many bytes.
        """
        cmd = ['docker', 'exec', '-i', self.name, 'cmd_runner.py']

        if stdin is None:
            cmd.append('--stdin_devnull')

        if max_num_processes is not None:
            cmd += ['--max_num_processes', str(max_num_processes)]

        if max_stack_size is not None:
            cmd += ['--max_stack_size', str(max_stack_size)]

        if max_virtual_memory is not None:
            cmd += ['--max_virtual_memory', str(max_virtual_memory)]

        if timeout is not None:
            cmd += ['--timeout', str(timeout)]

        if truncate_stdout is not None:
            cmd += ['--truncate_stdout', str(truncate_stdout)]

        if truncate_stderr is not None:
            cmd += ['--truncate_stderr', str(truncate_stderr)]

        if not as_root:
            cmd += ['--linux_user_id', str(self._linux_uid)]

        cmd += args

        if self.debug:
            print('running: {}'.format(cmd), flush=True)

        with tempfile.TemporaryFile() as f:
            try:
                subprocess.run(cmd, stdin=stdin, stdout=f, stderr=subprocess.PIPE, check=True)
                f.seek(0)
                json_len = int(f.readline().decode().rstrip())
                results_json = json.loads(f.read(json_len).decode())

                stdout_len = int(f.readline().decode().rstrip())
                stdout = tempfile.NamedTemporaryFile()
                stdout.write(f.read(stdout_len))
                stdout.seek(0)

                stderr_len = int(f.readline().decode().rstrip())
                stderr = tempfile.NamedTemporaryFile()
                stderr.write(f.read(stderr_len))
                stderr.seek(0)

                result = CompletedCommand(return_code=results_json['return_code'],
                                          timed_out=results_json['timed_out'],
                                          stdout=stdout,
                                          stderr=stderr,
                                          stdout_truncated=results_json['stdout_truncated'],
                                          stderr_truncated=results_json['stderr_truncated'])

                if (result.return_code != 0 or results_json['timed_out']) and check:
                    raise subprocess.CalledProcessError(
                        result.return_code, cmd,
                        output=result.stdout, stderr=result.stderr)

                return result
            except subprocess.CalledProcessError as e:
                f.seek(0)
                print(f.read())
                print(e.stderr)
                raise

def
run_command
(
self
,
args
:
List
[
str
]
,
max_num_processes
:
int
=
,
max_stack_size
:
int
=
,
max_virtual_memory
:
int
=
,
as_root
:
bool
=
False
,
stdin
:
FileIO
=
,
timeout
:
int
=
,
check
:
bool
=
False
,
truncate_stdout
:
int
=
,
truncate_stderr
:
int
=
)
->
'CompletedCommand'
:
cmd
=
[
'docker'
,
'exec'
,
'-i'
,
self
.
name
,
'cmd_runner.py'
]
if
stdin
is
:
cmd
.
append
(
'--stdin_devnull'
)
if
max_num_processes
is
not
:
cmd
+=
[
'--max_num_processes'
,
str
(
max_num_processes
)
]
if
max_stack_size
is
not
:
cmd
+=
[
'--max_stack_size'
,
str
(
max_stack_size
)
]
if
max_virtual_memory
is
not
:
cmd
+=
[
'--max_virtual_memory'
,
str
(
max_virtual_memory
)
]
if
timeout
is
not
:
cmd
+=
[
'--timeout'
,
str
(
timeout
)
]
if
truncate_stdout
is
not
:
cmd
+=
[
'--truncate_stdout'
,
str
(
truncate_stdout
)
]
if
truncate_stderr
is
not
:
cmd
+=
[
'--truncate_stderr'
,
str
(
truncate_stderr
)
]
if
not
as_root
:
cmd
+=
[
'--linux_user_id'
,
str
(
self
.
_linux_uid
)
]
cmd
+=
args
if
self
.
debug
:
print
(
'running: {}'
.
format
(
cmd
)
,
flush
=
True
)
with
tempfile
.
TemporaryFile
(
)
as
f
:
try
:
subprocess
.
run
(
cmd
,
stdin
=
stdin
,
stdout
=
f
,
stderr
=
subprocess
.
PIPE
,
check
=
True
)
f
.
seek
(
0
)
json_len
=
int
(
f
.
readline
(
)
.
decode
(
)
.
rstrip
(
)
)
results_json
=
json
.
loads
(
f
.
read
(
json_len
)
.
decode
(
)
)
stdout_len
=
int
(
f
.
readline
(
)
.
decode
(
)
.
rstrip
(
)
)
stdout
=
tempfile
.
NamedTemporaryFile
(
)
stdout
.
write
(
f
.
read
(
stdout_len
)
)
stdout
.
seek
(
0
)
stderr_len
=
int
(
f
.
readline
(
)
.
decode
(
)
.
rstrip
(
)
)
stderr
=
tempfile
.
NamedTemporaryFile
(
)
stderr
.
write
(
f
.
read
(
stderr_len
)
)
stderr
.
seek
(
0
)
result
=
CompletedCommand
(
return_code
=
results_json
[
'return_code'
]
,
timed_out
=
results_json
[
'timed_out'
]
,
stdout
=
stdout
,
stderr
=
stderr
,
stdout_truncated
=
results_json
[
'stdout_truncated'
]
,
stderr_truncated
=
results_json
[
'stderr_truncated'
]
)
if
(
result
.
return_code
!=
0
or
results_json
[
'timed_out'
]
)
and
check
:
raise
subprocess
.
CalledProcessError
(
result
.
return_code
,
cmd
,
output
=
result
.
stdout
,
stderr
=
result
.
stderr
)
return
result
except
subprocess
.
CalledProcessError
as
e
:
f
.
seek
(
0
)
print
(
f
.
read
(
)
)
print
(
e
.
stderr
)
raise

Runs a command inside the sandbox and returns the results .


def add_files(self, *filenames: str, owner: str=SANDBOX_USERNAME, read_only: bool=False):
        """
        Copies the specified files into the working directory of this
        sandbox.
        The filenames specified can be absolute paths or relative paths
        to the current working directory.

        :param owner: The name of a user who should be granted ownership of
            the newly added files.
            Must be either autograder_sandbox.SANDBOX_USERNAME or 'root',
            otherwise ValueError will be raised.
        :param read_only: If true, the new files' permissions will be set to
            read-only.
        """
        if owner != SANDBOX_USERNAME and owner != 'root':
            raise ValueError('Invalid value for parameter "owner": {}'.format(owner))

        with tempfile.TemporaryFile() as f, \
                tarfile.TarFile(fileobj=f, mode='w') as tar_file:
            for filename in filenames:
                tar_file.add(filename, arcname=os.path.basename(filename))

            f.seek(0)
            subprocess.check_call(
                ['docker', 'cp', '-',
                 self.name + ':' + SANDBOX_WORKING_DIR_NAME],
                stdin=f)

            file_basenames = [os.path.basename(filename) for filename in filenames]
            if owner == SANDBOX_USERNAME:
                self._chown_files(file_basenames)

            if read_only:
                chmod_cmd = ['chmod', '444'] + file_basenames
                self.run_command(chmod_cmd, as_root=True)

Copies the specified files into the working directory of this sandbox . The filenames specified can be absolute paths or relative paths to the current working directory .


def add_and_rename_file(self, filename: str, new_filename: str) -> None:
        """
        Copies the specified file into the working directory of this
        sandbox and renames it to new_filename.
        """
        dest = os.path.join(
            self.name + ':' + SANDBOX_WORKING_DIR_NAME,
            new_filename)
        subprocess.check_call(['docker', 'cp', filename, dest])
        self._chown_files([new_filename])

def add_and_rename_file ( self , filename : str , new_filename : str ) -> None : dest = os . path . join ( self . name + ':' + SANDBOX_WORKING_DIR_NAME , new_filename ) subprocess . check_call ( [ 'docker' , 'cp' , filename , dest ] ) self . _chown_files ( [ new_filename ] )

Copies the specified file into the working directory of this sandbox and renames it to new_filename .


def get_enrollments_for_course(self, course_id, params={}):
        """
        Return a list of all enrollments for the passed course_id.

        https://canvas.instructure.com/doc/api/enrollments.html#method.enrollments_api.index
        """
        url = COURSES_API.format(course_id) + "/enrollments"

        enrollments = []
        for datum in self._get_paged_resource(url, params=params):
            enrollments.append(CanvasEnrollment(data=datum))

        return enrollments

def get_enrollments_for_course ( self , course_id , params = { } ) : url = COURSES_API . format ( course_id ) + "/enrollments" enrollments = [ ] for datum in self . _get_paged_resource ( url , params = params ) : enrollments . append ( CanvasEnrollment ( data = datum ) ) return enrollments

Return a list of all enrollments for the passed course_id .


def get_enrollments_for_course_by_sis_id(self, sis_course_id, params={}):
        """
        Return a list of all enrollments for the passed course sis id.
        """
        return self.get_enrollments_for_course(
            self._sis_id(sis_course_id, sis_field="course"), params)

def get_enrollments_for_course_by_sis_id ( self , sis_course_id , params = { } ) : return self . get_enrollments_for_course ( self . _sis_id ( sis_course_id , sis_field = "course" ) , params )

Return a list of all enrollments for the passed course sis id .


def get_enrollments_for_section(self, section_id, params={}):
        """
        Return a list of all enrollments for the passed section_id.

        https://canvas.instructure.com/doc/api/enrollments.html#method.enrollments_api.index
        """
        url = SECTIONS_API.format(section_id) + "/enrollments"

        enrollments = []
        for datum in self._get_paged_resource(url, params=params):
            enrollments.append(CanvasEnrollment(data=datum))

        return enrollments

def get_enrollments_for_section ( self , section_id , params = { } ) : url = SECTIONS_API . format ( section_id ) + "/enrollments" enrollments = [ ] for datum in self . _get_paged_resource ( url , params = params ) : enrollments . append ( CanvasEnrollment ( data = datum ) ) return enrollments

Return a list of all enrollments for the passed section_id .


def get_enrollments_for_section_by_sis_id(self, sis_section_id, params={}):
        """
        Return a list of all enrollments for the passed section sis id.
        """
        return self.get_enrollments_for_section(
            self._sis_id(sis_section_id, sis_field="section"), params)

def get_enrollments_for_section_by_sis_id ( self , sis_section_id , params = { } ) : return self . get_enrollments_for_section ( self . _sis_id ( sis_section_id , sis_field = "section" ) , params )

Return a list of all enrollments for the passed section sis id .


def get_enrollments_for_regid(self, regid, params={},
                                  include_courses=True):
        """
        Return a list of enrollments for the passed user regid.

        https://canvas.instructure.com/doc/api/enrollments.html#method.enrollments_api.index
        """
        sis_user_id = self._sis_id(regid, sis_field="user")
        url = USERS_API.format(sis_user_id) + "/enrollments"

        courses = Courses() if include_courses else None

        enrollments = []
        for datum in self._get_paged_resource(url, params=params):
            enrollment = CanvasEnrollment(data=datum)
            if include_courses:
                course_id = datum["course_id"]
                course = courses.get_course(course_id)

                if course.sis_course_id is not None:
                    enrollment.course = course
                    # the following 3 lines are not removed
                    # to be backward compatible.
                    enrollment.course_url = course.course_url
                    enrollment.course_name = course.name
                    enrollment.sis_course_id = course.sis_course_id
            else:
                enrollment.course_url = re.sub(
                    r'/users/\d+$', '', enrollment.html_url)

            enrollments.append(enrollment)
        return enrollments

def
get_enrollments_for_regid
(
self
,
regid
,
params
=
{
}
,
include_courses
=
True
)
:
sis_user_id
=
self
.
_sis_id
(
regid
,
sis_field
=
"user"
)
url
=
USERS_API
.
format
(
sis_user_id
)
+
"/enrollments"
courses
=
Courses
(
)
if
include_courses
else
enrollments
=
[
]
for
datum
in
self
.
_get_paged_resource
(
url
,
params
=
params
)
:
enrollment
=
CanvasEnrollment
(
data
=
datum
)
if
include_courses
:
course_id
=
datum
[
"course_id"
]
course
=
courses
.
get_course
(
course_id
)
if
course
.
sis_course_id
is
not
:
enrollment
.
course
=
course
# the following 3 lines are not removed
# to be backward compatible.
enrollment
.
course_url
=
course
.
course_url
enrollment
.
course_name
=
course
.
name
enrollment
.
sis_course_id
=
course
.
sis_course_id
else
:
enrollment
.
course_url
=
re
.
sub
(
r'/users/\d+$'
,
''
,
enrollment
.
html_url
)
enrollments
.
append
(
enrollment
)
return
enrollments

Return a list of enrollments for the passed user regid .


def enroll_user(self, course_id, user_id, enrollment_type, params=None):
        """
        Enroll a user into a course.

        https://canvas.instructure.com/doc/api/enrollments.html#method.enrollments_api.create
        """
        url = COURSES_API.format(course_id) + "/enrollments"

        if not params:
            params = {}

        params["user_id"] = user_id
        params["type"] = enrollment_type

        data = self._post_resource(url, {"enrollment": params})
        return CanvasEnrollment(data=data)

def enroll_user ( self , course_id , user_id , enrollment_type , params = None ) : url = COURSES_API . format ( course_id ) + "/enrollments" if not params : params = { } params [ "user_id" ] = user_id params [ "type" ] = enrollment_type data = self . _post_resource ( url , { "enrollment" : params } ) return CanvasEnrollment ( data = data )


def get_roles_in_account(self, account_id, params={}):
        """
        List the roles for an account, for the passed Canvas account ID.

        https://canvas.instructure.com/doc/api/roles.html#method.role_overrides.api_index
        """
        url = ACCOUNTS_API.format(account_id) + "/roles"

        roles = []
        for datum in self._get_resource(url, params=params):
            roles.append(CanvasRole(data=datum))
        return roles

def get_roles_in_account ( self , account_id , params = { } ) : url = ACCOUNTS_API . format ( account_id ) + "/roles" roles = [ ] for datum in self . _get_resource ( url , params = params ) : roles . append ( CanvasRole ( data = datum ) ) return roles

List the roles for an account for the passed Canvas account ID .


def get_roles_by_account_sis_id(self, account_sis_id, params={}):
        """
        List the roles for an account, for the passed account SIS ID.
        """
        return self.get_roles_in_account(self._sis_id(account_sis_id,
                                                      sis_field="account"),
                                         params)

def get_roles_by_account_sis_id ( self , account_sis_id , params = { } ) : return self . get_roles_in_account ( self . _sis_id ( account_sis_id , sis_field = "account" ) , params )

List the roles for an account for the passed account SIS ID .


def get_effective_course_roles_in_account(self, account_id):
        """
        List all course roles available to an account, for the passed Canvas
        account ID, including course roles inherited from parent accounts.
        """
        course_roles = []
        params = {"show_inherited": "1"}
        for role in self.get_roles_in_account(account_id, params):
            if role.base_role_type != "AccountMembership":
                course_roles.append(role)
        return course_roles

def get_effective_course_roles_in_account ( self , account_id ) : course_roles = [ ] params = { "show_inherited" : "1" } for role in self . get_roles_in_account ( account_id , params ) : if role . base_role_type != "AccountMembership" : course_roles . append ( role ) return course_roles

List all course roles available to an account for the passed Canvas account ID including course roles inherited from parent accounts .


def get_role(self, account_id, role_id):
        """
        Get information about a single role, for the passed Canvas account ID.

        https://canvas.instructure.com/doc/api/roles.html#method.role_overrides.show
        """
        url = ACCOUNTS_API.format(account_id) + "/roles/{}".format(role_id)
        return CanvasRole(data=self._get_resource(url))

def get_role ( self , account_id , role_id ) : url = ACCOUNTS_API . format ( account_id ) + "/roles/{}" . format ( role_id ) return CanvasRole ( data = self . _get_resource ( url ) )

Get information about a single role for the passed Canvas account ID .


def get_role_by_account_sis_id(self, account_sis_id, role_id):
        """
        Get information about a single role, for the passed account SIS ID.
        """
        return self.get_role(self._sis_id(account_sis_id, sis_field="account"),
                             role_id)

def get_role_by_account_sis_id ( self , account_sis_id , role_id ) : return self . get_role ( self . _sis_id ( account_sis_id , sis_field = "account" ) , role_id )

Get information about a single role for the passed account SIS ID .


def get_course(self, course_id, params={}):
        """
        Return course resource for given canvas course id.

        https://canvas.instructure.com/doc/api/courses.html#method.courses.show
        """
        include = params.get("include", [])
        if "term" not in include:
            include.append("term")
        params["include"] = include

        url = COURSES_API.format(course_id)
        return CanvasCourse(data=self._get_resource(url, params=params))

def get_course ( self , course_id , params = { } ) : include = params . get ( "include" , [ ] ) if "term" not in include : include . append ( "term" ) params [ "include" ] = include url = COURSES_API . format ( course_id ) return CanvasCourse ( data = self . _get_resource ( url , params = params ) )

Return course resource for given canvas course id .


def get_course_by_sis_id(self, sis_course_id, params={}):
        """
        Return course resource for given sis id.
        """
        return self.get_course(self._sis_id(sis_course_id, sis_field="course"),
                               params)

def get_course_by_sis_id ( self , sis_course_id , params = { } ) : return self . get_course ( self . _sis_id ( sis_course_id , sis_field = "course" ) , params )

Return course resource for given sis id .


def get_courses_in_account(self, account_id, params={}):
        """
        Returns a list of courses for the passed account ID.

        https://canvas.instructure.com/doc/api/accounts.html#method.accounts.courses_api
        """
        if "published" in params:
            params["published"] = "true" if params["published"] else ""

        url = ACCOUNTS_API.format(account_id) + "/courses"

        courses = []
        for data in self._get_paged_resource(url, params=params):
            courses.append(CanvasCourse(data=data))
        return courses

def get_courses_in_account ( self , account_id , params = { } ) : if "published" in params : params [ "published" ] = "true" if params [ "published" ] else "" url = ACCOUNTS_API . format ( account_id ) + "/courses" courses = [ ] for data in self . _get_paged_resource ( url , params = params ) : courses . append ( CanvasCourse ( data = data ) ) return courses

Returns a list of courses for the passed account ID .


def get_courses_in_account_by_sis_id(self, sis_account_id, params={}):
        """
        Return a list of courses for the passed account SIS ID.
        """
        return self.get_courses_in_account(
            self._sis_id(sis_account_id, sis_field="account"), params)

def get_courses_in_account_by_sis_id ( self , sis_account_id , params = { } ) : return self . get_courses_in_account ( self . _sis_id ( sis_account_id , sis_field = "account" ) , params )

Return a list of courses for the passed account SIS ID .


def get_published_courses_in_account(self, account_id, params={}):
        """
        Return a list of published courses for the passed account ID.
        """
        params["published"] = True
        return self.get_courses_in_account(account_id, params)

def get_published_courses_in_account ( self , account_id , params = { } ) : params [ "published" ] = True return self . get_courses_in_account ( account_id , params )

Return a list of published courses for the passed account ID .


def get_published_courses_in_account_by_sis_id(self, sis_account_id,
                                                   params={}):
        """
        Return a list of published courses for the passed account SIS ID.
        """

        return self.get_published_courses_in_account(
            self._sis_id(sis_account_id, sis_field="account"), params)

Return a list of published courses for the passed account SIS ID .


def get_courses_for_regid(self, regid, params={}):
        """
        Return a list of courses for the passed regid.

        https://canvas.instructure.com/doc/api/courses.html#method.courses.index
        """
        self._as_user = regid
        data = self._get_resource("/api/v1/courses", params=params)
        self._as_user = None

        courses = []
        for datum in data:
            if "sis_course_id" in datum:
                courses.append(CanvasCourse(data=datum))
            else:
                courses.append(self.get_course(datum["id"], params))

        return courses

def get_courses_for_regid ( self , regid , params = { } ) : self . _as_user = regid data = self . _get_resource ( "/api/v1/courses" , params = params ) self . _as_user = None courses = [ ] for datum in data : if "sis_course_id" in datum : courses . append ( CanvasCourse ( data = datum ) ) else : courses . append ( self . get_course ( datum [ "id" ] , params ) ) return courses

Return a list of courses for the passed regid .


def create_course(self, account_id, course_name):
        """
        Create a canvas course with the given subaccount id and course name.

        https://canvas.instructure.com/doc/api/courses.html#method.courses.create
        """
        url = ACCOUNTS_API.format(account_id) + "/courses"
        body = {"course": {"name": course_name}}
        return CanvasCourse(data=self._post_resource(url, body))

def create_course ( self , account_id , course_name ) : url = ACCOUNTS_API . format ( account_id ) + "/courses" body = { "course" : { "name" : course_name } } return CanvasCourse ( data = self . _post_resource ( url , body ) )

Create a canvas course with the given subaccount id and course name .


def update_sis_id(self, course_id, sis_course_id):
        """
        Updates the SIS ID for the course identified by the passed course ID.

        https://canvas.instructure.com/doc/api/courses.html#method.courses.update
        """
        url = COURSES_API.format(course_id)
        body = {"course": {"sis_course_id": sis_course_id}}
        return CanvasCourse(data=self._put_resource(url, body))

def update_sis_id ( self , course_id , sis_course_id ) : url = COURSES_API . format ( course_id ) body = { "course" : { "sis_course_id" : sis_course_id } } return CanvasCourse ( data = self . _put_resource ( url , body ) )

Updates the SIS ID for the course identified by the passed course ID .


def get_activity_by_account(self, account_id, term_id):
        """
        Returns participation data for the given account_id and term_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.department_participation
        """
        url = ("/api/v1/accounts/sis_account_id:%s/analytics/"
               "terms/sis_term_id:%s/activity.json") % (account_id, term_id)
        return self._get_resource(url)

Returns participation data for the given account_id and term_id .


def get_grades_by_account(self, account_id, term_id):
        """
        Returns grade data for the given account_id and term_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.department_grades
        """
        url = ("/api/v1/accounts/sis_account_id:%s/analytics/"
               "terms/sis_term_id:%s/grades.json") % (account_id, term_id)
        return self._get_resource(url)

Returns grade data for the given account_id and term_id .


def get_statistics_by_account(self, account_id, term_id):
        """
        Returns statistics for the given account_id and term_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.department_statistics
        """
        url = ("/api/v1/accounts/sis_account_id:%s/analytics/"
               "terms/sis_term_id:%s/statistics.json") % (account_id, term_id)
        return self._get_resource(url)

Returns statistics for the given account_id and term_id .


def get_activity_by_sis_course_id(self, sis_course_id):
        """
        Returns participation data for the given sis_course_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.course_participation
        """
        url = "/api/v1/courses/%s/analytics/activity.json" % (
            self._sis_id(sis_course_id, sis_field="course"))
        return self._get_resource(url)

Returns participation data for the given sis_course_id .


def get_assignments_by_sis_course_id(self, sis_course_id):
        """
        Returns assignment data for the given course_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.course_assignments
        """
        url = "/api/v1/courses/%s/analytics/assignments.json" % (
            self._sis_id(sis_course_id, sis_field="course"))
        return self._get_resource(url)

Returns assignment data for the given course_id .


def get_student_summaries_by_sis_course_id(self, sis_course_id):
        """
        Returns per-student data for the given course_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.course_student_summaries
        """
        url = "/api/v1/courses/%s/analytics/student_summaries.json" % (
            self._sis_id(sis_course_id, sis_field="course"))
        return self._get_resource(url)

Returns per - student data for the given course_id .


def get_student_activity_for_sis_course_id_and_sis_user_id(
            self, sis_user_id, sis_course_id):
        """
        Returns student activity data for the given user_id and course_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.student_in_course_participation
        """
        url = ("/api/v1/courses/%s/analytics/users/"
               "sis_user_id:%s/activity.json") % (
            self._sis_id(sis_course_id, sis_field="course"), sis_user_id)
        return self._get_resource(url)

Returns student activity data for the given user_id and course_id .


def get_student_messaging_for_sis_course_id_and_sis_user_id(
            self, sis_user_id, sis_course_id):
        """
        Returns student messaging data for the given user_id and course_id.

        https://canvas.instructure.com/doc/api/analytics.html#method.analytics_api.student_in_course_messaging
        """
        url = ("/api/v1/courses/%s/analytics/"
               "users/sis_user_id:%s/communication.json") % (
            self._sis_id(sis_course_id, sis_field="course"), sis_user_id)
        return self._get_resource(url)

Returns student messaging data for the given user_id and course_id .


def get_external_tools_in_account(self, account_id, params={}):
        """
        Return external tools for the passed canvas account id.

        https://canvas.instructure.com/doc/api/external_tools.html#method.external_tools.index
        """
        url = ACCOUNTS_API.format(account_id) + "/external_tools"

        external_tools = []
        for data in self._get_paged_resource(url, params=params):
            external_tools.append(data)
        return external_tools

def get_external_tools_in_account ( self , account_id , params = { } ) : url = ACCOUNTS_API . format ( account_id ) + "/external_tools" external_tools = [ ] for data in self . _get_paged_resource ( url , params = params ) : external_tools . append ( data ) return external_tools

Return external tools for the passed canvas account id .


def get_external_tools_in_course(self, course_id, params={}):
        """
        Return external tools for the passed canvas course id.

        https://canvas.instructure.com/doc/api/external_tools.html#method.external_tools.index
        """
        url = COURSES_API.format(course_id) + "/external_tools"

        external_tools = []
        for data in self._get_paged_resource(url, params=params):
            external_tools.append(data)
        return external_tools

def get_external_tools_in_course ( self , course_id , params = { } ) : url = COURSES_API . format ( course_id ) + "/external_tools" external_tools = [ ] for data in self . _get_paged_resource ( url , params = params ) : external_tools . append ( data ) return external_tools

Return external tools for the passed canvas course id .


def _create_external_tool(self, context, context_id, json_data):
        """
        Create an external tool using the passed json_data.

        context is either COURSES_API or ACCOUNTS_API.
        context_id is the Canvas course_id or account_id, depending on context.

        https://canvas.instructure.com/doc/api/external_tools.html#method.external_tools.create
        """
        url = context.format(context_id) + "/external_tools"
        return self._post_resource(url, body=json_data)

def _create_external_tool ( self , context , context_id , json_data ) : url = context . format ( context_id ) + "/external_tools" return self . _post_resource ( url , body = json_data )

Create an external tool using the passed json_data .


def _update_external_tool(self, context, context_id, external_tool_id,
                              json_data):
        """
        Update the external tool identified by external_tool_id with the passed
        json data.

        context is either COURSES_API or ACCOUNTS_API.
        context_id is the course_id or account_id, depending on context

        https://canvas.instructure.com/doc/api/external_tools.html#method.external_tools.update
        """
        url = context.format(context_id) + "/external_tools/{}".format(
            external_tool_id)
        return self._put_resource(url, body=json_data)

def _update_external_tool ( self , context , context_id , external_tool_id , json_data ) : url = context . format ( context_id ) + "/external_tools/{}" . format ( external_tool_id ) return self . _put_resource ( url , body = json_data )

Update the external tool identified by external_tool_id with the passed json data .


def _delete_external_tool(self, context, context_id, external_tool_id):
        """
        Delete the external tool identified by external_tool_id.

        context is either COURSES_API or ACCOUNTS_API.
        context_id is the course_id or account_id, depending on context

        https://canvas.instructure.com/doc/api/external_tools.html#method.external_tools.destroy
        """
        url = context.format(context_id) + "/external_tools/{}".format(
            external_tool_id)
        response = self._delete_resource(url)
        return True

def _delete_external_tool ( self , context , context_id , external_tool_id ) : url = context . format ( context_id ) + "/external_tools/{}" . format ( external_tool_id ) response = self . _delete_resource ( url ) return True

Delete the external tool identified by external_tool_id .


def check_required(obj, required_parameters):
    """
    Check if a parameter is available on an object

    :param obj: Object
    :param required_parameters: list of parameters
    :return:
    """
    for parameter in required_parameters:
        if not hasattr(obj, parameter) or getattr(obj, parameter) is None:
            raise DesignError("parameter '%s' must be set for '%s' object." % (parameter, obj.base_type))


def get_user(self, user_id):
        """
        Returns user profile data.

        https://canvas.instructure.com/doc/api/users.html#method.profile.settings
        """
        url = USERS_API.format(user_id) + "/profile"
        return CanvasUser(data=self._get_resource(url))

def get_user ( self , user_id ) : url = USERS_API . format ( user_id ) + "/profile" return CanvasUser ( data = self . _get_resource ( url ) )


def get_users_for_course(self, course_id, params={}):
        """
        Returns a list of users for the given course id.
        """
        url = COURSES_API.format(course_id) + "/users"
        data = self._get_paged_resource(url, params=params)
        users = []
        for datum in data:
            users.append(CanvasUser(data=datum))
        return users

def get_users_for_course ( self , course_id , params = { } ) : url = COURSES_API . format ( course_id ) + "/users" data = self . _get_paged_resource ( url , params = params ) users = [ ] for datum in data : users . append ( CanvasUser ( data = datum ) ) return users

Returns a list of users for the given course id .


def get_users_for_sis_course_id(self, sis_course_id, params={}):
        """
        Returns a list of users for the given sis course id.
        """
        return self.get_users_for_course(
            self._sis_id(sis_course_id, sis_field="course"), params)

def get_users_for_sis_course_id ( self , sis_course_id , params = { } ) : return self . get_users_for_course ( self . _sis_id ( sis_course_id , sis_field = "course" ) , params )

Returns a list of users for the given sis course id .


def create_user(self, user, account_id=None):
        """
        Create and return a new user and pseudonym for an account.

        https://canvas.instructure.com/doc/api/users.html#method.users.create
        """
        if account_id is None:
            account_id = self._canvas_account_id
            if account_id is None:
                raise MissingAccountID()

        url = ACCOUNTS_API.format(account_id) + "/users"

        data = self._post_resource(url, user.post_data())
        return CanvasUser(data=data)

def create_user ( self , user , account_id = None ) : if account_id is None : account_id = self . _canvas_account_id if account_id is None : raise MissingAccountID ( ) url = ACCOUNTS_API . format ( account_id ) + "/users" data = self . _post_resource ( url , user . post_data ( ) ) return CanvasUser ( data = data )

Create and return a new user and pseudonym for an account .


def get_user_logins(self, user_id, params={}):
        """
        Return a user's logins for the given user_id.

        https://canvas.instructure.com/doc/api/logins.html#method.pseudonyms.index
        """
        url = USERS_API.format(user_id) + "/logins"

        data = self._get_paged_resource(url, params=params)

        logins = []
        for login_data in data:
            logins.append(Login(data=login_data))

        return logins

def get_user_logins ( self , user_id , params = { } ) : url = USERS_API . format ( user_id ) + "/logins" data = self . _get_paged_resource ( url , params = params ) logins = [ ] for login_data in data : logins . append ( Login ( data = login_data ) ) return logins

Return a user s logins for the given user_id .


def update_user_login(self, login, account_id=None):
        """
        Update an existing login for a user in the given account.

        https://canvas.instructure.com/doc/api/logins.html#method.pseudonyms.update
        """
        if account_id is None:
            account_id = self._canvas_account_id
            if account_id is None:
                raise MissingAccountID

        login_id = login.login_id
        url = ACCOUNTS_API.format(account_id) + "/logins/{}".format(login_id)

        data = self._put_resource(url, login.put_data())
        return Login(data=data)

def update_user_login ( self , login , account_id = None ) : if account_id is None : account_id = self . _canvas_account_id if account_id is None : raise MissingAccountID login_id = login . login_id url = ACCOUNTS_API . format ( account_id ) + "/logins/{}" . format ( login_id ) data = self . _put_resource ( url , login . put_data ( ) ) return Login ( data = data )

Update an existing login for a user in the given account .


def _next_page(self, response):
        """
        return url path to next page of paginated data
        """
        for link in response.getheader("link", "").split(","):
            try:
                (url, rel) = link.split(";")
                if "next" in rel:
                    return url.lstrip("<").rstrip(">")
            except Exception:
                return

def _next_page ( self , response ) : for link in response . getheader ( "link" , "" ) . split ( "," ) : try : ( url , rel ) = link . split ( ";" ) if "next" in rel : return url . lstrip ( "<" ) . rstrip ( ">" ) except Exception : return


def _get_resource_url(self, url, auto_page, data_key):
        """
        Canvas GET method on a full url. Return representation of the
        requested resource, chasing pagination links to coalesce resources
        if indicated.
        """
        headers = {'Accept': 'application/json',
                   'Connection': 'keep-alive'}
        response = DAO.getURL(url, headers)

        if response.status != 200:
            raise DataFailureException(url, response.status, response.data)

        data = json.loads(response.data)

        self.next_page_url = self._next_page(response)
        if auto_page and self.next_page_url:
            if isinstance(data, list):
                data.extend(self._get_resource_url(self.next_page_url, True,
                                                   data_key))
            elif isinstance(data, dict) and data_key is not None:
                data[data_key].extend(self._get_resource_url(
                    self.next_page_url, True, data_key)[data_key])

        return data

def _get_resource_url ( self , url , auto_page , data_key ) : headers = { 'Accept' : 'application/json' , 'Connection' : 'keep-alive' } response = DAO . getURL ( url , headers ) if response . status != 200 : raise DataFailureException ( url , response . status , response . data ) data = json . loads ( response . data ) self . next_page_url = self . _next_page ( response ) if auto_page and self . next_page_url : if isinstance ( data , list ) : data . extend ( self . _get_resource_url ( self . next_page_url , True , data_key ) ) elif isinstance ( data , dict ) and data_key is not None : data [ data_key ] . extend ( self . _get_resource_url ( self . next_page_url , True , data_key ) [ data_key ] ) return data

Canvas GET method on a full url . Return representation of the requested resource chasing pagination links to coalesce resources if indicated .


def _get_paged_resource(self, url, params=None, data_key=None):
        """
        Canvas GET method. Return representation of the requested paged
        resource, either the requested page, or chase pagination links to
        coalesce resources.
        """
        if not params:
            params = {}

        self._set_as_user(params)

        auto_page = not ('page' in params or 'per_page' in params)

        if 'per_page' not in params and self._per_page != DEFAULT_PAGINATION:
            params["per_page"] = self._per_page

        full_url = url + self._params(params)
        return self._get_resource_url(full_url, auto_page, data_key)

def _get_paged_resource ( self , url , params = None , data_key = None ) : if not params : params = { } self . _set_as_user ( params ) auto_page = not ( 'page' in params or 'per_page' in params ) if 'per_page' not in params and self . _per_page != DEFAULT_PAGINATION : params [ "per_page" ] = self . _per_page full_url = url + self . _params ( params ) return self . _get_resource_url ( full_url , auto_page , data_key )

Canvas GET method . Return representation of the requested paged resource either the requested page or chase pagination links to coalesce resources .


def _get_resource(self, url, params=None, data_key=None):
        """
        Canvas GET method. Return representation of the requested resource.
        """
        if not params:
            params = {}

        self._set_as_user(params)

        full_url = url + self._params(params)

        return self._get_resource_url(full_url, True, data_key)

def _get_resource ( self , url , params = None , data_key = None ) : if not params : params = { } self . _set_as_user ( params ) full_url = url + self . _params ( params ) return self . _get_resource_url ( full_url , True , data_key )

Canvas GET method . Return representation of the requested resource .


def _put_resource(self, url, body):
        """
        Canvas PUT method.
        """
        params = {}
        self._set_as_user(params)
        headers = {'Content-Type': 'application/json',
                   'Accept': 'application/json',
                   'Connection': 'keep-alive'}
        url = url + self._params(params)
        response = DAO.putURL(url, headers, json.dumps(body))

        if not (response.status == 200 or response.status == 201 or
                response.status == 204):
            raise DataFailureException(url, response.status, response.data)

        return json.loads(response.data)

def _put_resource ( self , url , body ) : params = { } self . _set_as_user ( params ) headers = { 'Content-Type' : 'application/json' , 'Accept' : 'application/json' , 'Connection' : 'keep-alive' } url = url + self . _params ( params ) response = DAO . putURL ( url , headers , json . dumps ( body ) ) if not ( response . status == 200 or response . status == 201 or response . status == 204 ) : raise DataFailureException ( url , response . status , response . data ) return json . loads ( response . data )


def _post_resource(self, url, body):
        """
        Canvas POST method.
        """
        params = {}
        self._set_as_user(params)
        headers = {'Content-Type': 'application/json',
                   'Accept': 'application/json',
                   'Connection': 'keep-alive'}
        url = url + self._params(params)
        response = DAO.postURL(url, headers, json.dumps(body))

        if not (response.status == 200 or response.status == 204):
            raise DataFailureException(url, response.status, response.data)

        return json.loads(response.data)

def _post_resource ( self , url , body ) : params = { } self . _set_as_user ( params ) headers = { 'Content-Type' : 'application/json' , 'Accept' : 'application/json' , 'Connection' : 'keep-alive' } url = url + self . _params ( params ) response = DAO . postURL ( url , headers , json . dumps ( body ) ) if not ( response . status == 200 or response . status == 204 ) : raise DataFailureException ( url , response . status , response . data ) return json . loads ( response . data )


def _delete_resource(self, url):
        """
        Canvas DELETE method.
        """
        params = {}
        self._set_as_user(params)
        headers = {'Accept': 'application/json',
                   'Connection': 'keep-alive'}
        url = url + self._params(params)
        response = DAO.deleteURL(url, headers)

        if not (response.status == 200 or response.status == 204):
            raise DataFailureException(url, response.status, response.data)

        return response

def _delete_resource ( self , url ) : params = { } self . _set_as_user ( params ) headers = { 'Accept' : 'application/json' , 'Connection' : 'keep-alive' } url = url + self . _params ( params ) response = DAO . deleteURL ( url , headers ) if not ( response . status == 200 or response . status == 204 ) : raise DataFailureException ( url , response . status , response . data ) return response


def get_admins(self, account_id, params={}):
        """
        Return a list of the admins in the account.

        https://canvas.instructure.com/doc/api/admins.html#method.admins.index
        """
        url = ADMINS_API.format(account_id)

        admins = []
        for data in self._get_paged_resource(url, params=params):
            admins.append(CanvasAdmin(data=data))
        return admins

def get_admins ( self , account_id , params = { } ) : url = ADMINS_API . format ( account_id ) admins = [ ] for data in self . _get_paged_resource ( url , params = params ) : admins . append ( CanvasAdmin ( data = data ) ) return admins

Return a list of the admins in the account .


def create_admin(self, account_id, user_id, role):
        """
        Flag an existing user as an admin within the account.

        https://canvas.instructure.com/doc/api/admins.html#method.admins.create
        """
        url = ADMINS_API.format(account_id)
        body = {"user_id": unquote(str(user_id)),
                "role": role,
                "send_confirmation": False}

        return CanvasAdmin(data=self._post_resource(url, body))

def create_admin ( self , account_id , user_id , role ) : url = ADMINS_API . format ( account_id ) body = { "user_id" : unquote ( str ( user_id ) ) , "role" : role , "send_confirmation" : False } return CanvasAdmin ( data = self . _post_resource ( url , body ) )

Flag an existing user as an admin within the account .


def create_admin_by_sis_id(self, sis_account_id, user_id, role):
        """
        Flag an existing user as an admin within the account sis id.
        """
        return self.create_admin(self._sis_id(sis_account_id), user_id, role)

def create_admin_by_sis_id ( self , sis_account_id , user_id , role ) : return self . create_admin ( self . _sis_id ( sis_account_id ) , user_id , role )

Flag an existing user as an admin within the account sis id .


def delete_admin(self, account_id, user_id, role):
        """
        Remove an account admin role from a user.

        https://canvas.instructure.com/doc/api/admins.html#method.admins.destroy
        """
        url = ADMINS_API.format(account_id) + "/{}?role={}".format(
            user_id, quote(role))

        response = self._delete_resource(url)
        return True

def delete_admin ( self , account_id , user_id , role ) : url = ADMINS_API . format ( account_id ) + "/{}?role={}" . format ( user_id , quote ( role ) ) response = self . _delete_resource ( url ) return True

Remove an account admin role from a user .


def delete_admin_by_sis_id(self, sis_account_id, user_id, role):
        """
        Remove an account admin role from a user for the account sis id.
        """
        return self.delete_admin(self._sis_id(sis_account_id), user_id, role)

def delete_admin_by_sis_id ( self , sis_account_id , user_id , role ) : return self . delete_admin ( self . _sis_id ( sis_account_id ) , user_id , role )

Remove an account admin role from a user for the account sis id .


def create_grading_standard_for_course(self, course_id, name,
                                           grading_scheme, creator):
        """
        Create a new grading standard for the passed course.

        https://canvas.instructure.com/doc/api/grading_standards.html#method.grading_standards_api.create
        """
        url = COURSES_API.format(course_id) + "/grading_standards"
        body = {
            "title": name,
            "grading_scheme_entry": grading_scheme,
            "as_user_id": creator
        }

        return GradingStandard(data=self._post_resource(url, body))

def create_grading_standard_for_course ( self , course_id , name , grading_scheme , creator ) : url = COURSES_API . format ( course_id ) + "/grading_standards" body = { "title" : name , "grading_scheme_entry" : grading_scheme , "as_user_id" : creator } return GradingStandard ( data = self . _post_resource ( url , body ) )

Create a new grading standard for the passed course .


def get_section(self, section_id, params={}):
        """
        Return section resource for given canvas section id.

        https://canvas.instructure.com/doc/api/sections.html#method.sections.show
        """
        url = SECTIONS_API.format(section_id)
        return CanvasSection(data=self._get_resource(url, params=params))

def get_section ( self , section_id , params = { } ) : url = SECTIONS_API . format ( section_id ) return CanvasSection ( data = self . _get_resource ( url , params = params ) )

Return section resource for given canvas section id .


def get_section_by_sis_id(self, sis_section_id, params={}):
        """
        Return section resource for given sis id.
        """
        return self.get_section(
            self._sis_id(sis_section_id, sis_field="section"), params)

def get_section_by_sis_id ( self , sis_section_id , params = { } ) : return self . get_section ( self . _sis_id ( sis_section_id , sis_field = "section" ) , params )

Return section resource for given sis id .


def get_sections_in_course(self, course_id, params={}):
        """
        Return list of sections for the passed course ID.

        https://canvas.instructure.com/doc/api/sections.html#method.sections.index
        """
        url = COURSES_API.format(course_id) + "/sections"

        sections = []
        for data in self._get_paged_resource(url, params=params):
            sections.append(CanvasSection(data=data))

        return sections

def get_sections_in_course ( self , course_id , params = { } ) : url = COURSES_API . format ( course_id ) + "/sections" sections = [ ] for data in self . _get_paged_resource ( url , params = params ) : sections . append ( CanvasSection ( data = data ) ) return sections

Return list of sections for the passed course ID .


def get_sections_in_course_by_sis_id(self, sis_course_id, params={}):
        """
        Return list of sections for the passed course SIS ID.
        """
        return self.get_sections_in_course(
            self._sis_id(sis_course_id, sis_field="course"), params)

def get_sections_in_course_by_sis_id ( self , sis_course_id , params = { } ) : return self . get_sections_in_course ( self . _sis_id ( sis_course_id , sis_field = "course" ) , params )

Return list of sections for the passed course SIS ID .


def get_sections_with_students_in_course(self, course_id, params={}):
        """
        Return list of sections including students for the passed course ID.
        """
        include = params.get("include", [])
        if "students" not in include:
            include.append("students")
        params["include"] = include

        return self.get_sections_in_course(course_id, params)

def get_sections_with_students_in_course ( self , course_id , params = { } ) : include = params . get ( "include" , [ ] ) if "students" not in include : include . append ( "students" ) params [ "include" ] = include return self . get_sections_in_course ( course_id , params )

Return list of sections including students for the passed course ID .


def get_sections_with_students_in_course_by_sis_id(self, sis_course_id,
                                                       params={}):
        """
        Return list of sections including students for the passed sis ID.
        """
        return self.get_sections_with_students_in_course(
            self._sis_id(sis_course_id, sis_field="course"), params)

Return list of sections including students for the passed sis ID .


def create_section(self, course_id, name, sis_section_id):
        """
        Create a canvas section in the given course id.

        https://canvas.instructure.com/doc/api/sections.html#method.sections.create
        """
        url = COURSES_API.format(course_id) + "/sections"
        body = {"course_section": {"name": name,
                                   "sis_section_id": sis_section_id}}

        return CanvasSection(data=self._post_resource(url, body))

def create_section ( self , course_id , name , sis_section_id ) : url = COURSES_API . format ( course_id ) + "/sections" body = { "course_section" : { "name" : name , "sis_section_id" : sis_section_id } } return CanvasSection ( data = self . _post_resource ( url , body ) )

Create a canvas section in the given course id .


def update_section(self, section_id, name, sis_section_id):
        """
        Update a canvas section with the given section id.

        https://canvas.instructure.com/doc/api/sections.html#method.sections.update
        """
        url = SECTIONS_API.format(section_id)
        body = {"course_section": {}}

        if name:
            body["course_section"]["name"] = name

        if sis_section_id:
            body["course_section"]["sis_section_id"] = sis_section_id

        return CanvasSection(data=self._put_resource(url, body))

def update_section ( self , section_id , name , sis_section_id ) : url = SECTIONS_API . format ( section_id ) body = { "course_section" : { } } if name : body [ "course_section" ] [ "name" ] = name if sis_section_id : body [ "course_section" ] [ "sis_section_id" ] = sis_section_id return CanvasSection ( data = self . _put_resource ( url , body ) )

Update a canvas section with the given section id .


def get_quizzes(self, course_id):
        """
        List quizzes for a given course

        https://canvas.instructure.com/doc/api/quizzes.html#method.quizzes_api.index
        """
        url = QUIZZES_API.format(course_id)
        data = self._get_resource(url)
        quizzes = []
        for datum in data:
            quizzes.append(Quiz(data=datum))
        return quizzes

def get_quizzes ( self , course_id ) : url = QUIZZES_API . format ( course_id ) data = self . _get_resource ( url ) quizzes = [ ] for datum in data : quizzes . append ( Quiz ( data = datum ) ) return quizzes


def get_account(self, account_id):
        """
        Return account resource for given canvas account id.

        https://canvas.instructure.com/doc/api/accounts.html#method.accounts.show
        """
        url = ACCOUNTS_API.format(account_id)
        return CanvasAccount(data=self._get_resource(url))

def get_account ( self , account_id ) : url = ACCOUNTS_API . format ( account_id ) return CanvasAccount ( data = self . _get_resource ( url ) )

Return account resource for given canvas account id .


def get_sub_accounts(self, account_id, params={}):
        """
        Return list of subaccounts within the account with the passed
        canvas id.

        https://canvas.instructure.com/doc/api/accounts.html#method.accounts.sub_accounts
        """
        url = ACCOUNTS_API.format(account_id) + "/sub_accounts"

        accounts = []
        for datum in self._get_paged_resource(url, params=params):
            accounts.append(CanvasAccount(data=datum))

        return accounts

def get_sub_accounts ( self , account_id , params = { } ) : url = ACCOUNTS_API . format ( account_id ) + "/sub_accounts" accounts = [ ] for datum in self . _get_paged_resource ( url , params = params ) : accounts . append ( CanvasAccount ( data = datum ) ) return accounts

Return list of subaccounts within the account with the passed canvas id .


def update_account(self, account):
        """
        Update the passed account. Returns the updated account.

        https://canvas.instructure.com/doc/api/accounts.html#method.accounts.update
        """
        url = ACCOUNTS_API.format(account.account_id)
        body = {"account": {"name": account.name}}

        return CanvasAccount(data=self._put_resource(url, body))

def update_account ( self , account ) : url = ACCOUNTS_API . format ( account . account_id ) body = { "account" : { "name" : account . name } } return CanvasAccount ( data = self . _put_resource ( url , body ) )

Update the passed account . Returns the updated account .


def update_sis_id(self, account_id, sis_account_id):
        """
        Updates the SIS ID for the account identified by the passed account ID.

        https://canvas.instructure.com/doc/api/accounts.html#method.accounts.update
        """
        if account_id == self._canvas_account_id:
            raise Exception("SIS ID cannot be updated for the root account")

        url = ACCOUNTS_API.format(account_id)
        body = {"account": {"sis_account_id": sis_account_id}}

        return CanvasAccount(data=self._put_resource(url, body))

Updates the SIS ID for the account identified by the passed account ID .


def get_auth_settings(self, account_id):
        """
        Return the authentication settings for the passed account_id.

        https://canvas.instructure.com/doc/api/authentication_providers.html#method.account_authorization_configs.show_sso_settings
        """
        url = ACCOUNTS_API.format(account_id) + "/sso_settings"
        return CanvasSSOSettings(data=self._get_resource(url))

def get_auth_settings ( self , account_id ) : url = ACCOUNTS_API . format ( account_id ) + "/sso_settings" return CanvasSSOSettings ( data = self . _get_resource ( url ) )

Return the authentication settings for the passed account_id .


def update_auth_settings(self, account_id, auth_settings):
        """
        Update the authentication settings for the passed account_id.

        https://canvas.instructure.com/doc/api/authentication_providers.html#method.account_authorization_configs.update_sso_settings
        """
        url = ACCOUNTS_API.format(account_id) + "/sso_settings"
        data = self._put_resource(url, auth_settings.json_data())
        return CanvasSSOSettings(data=data)

def update_auth_settings ( self , account_id , auth_settings ) : url = ACCOUNTS_API . format ( account_id ) + "/sso_settings" data = self . _put_resource ( url , auth_settings . json_data ( ) ) return CanvasSSOSettings ( data = data )

Update the authentication settings for the passed account_id .


def get_term_by_sis_id(self, sis_term_id):
        """
        Return a term resource for the passed SIS ID.
        """
        for term in self.get_all_terms():
            if term.sis_term_id == sis_term_id:
                return term

def get_term_by_sis_id ( self , sis_term_id ) : for term in self . get_all_terms ( ) : if term . sis_term_id == sis_term_id : return term

Return a term resource for the passed SIS ID .


def import_str(self, csv, params={}):
        """
        Imports a CSV string.

        https://canvas.instructure.com/doc/api/sis_imports.html#method.sis_imports_api.create
        """
        if not self._canvas_account_id:
            raise MissingAccountID()

        params["import_type"] = SISImportModel.CSV_IMPORT_TYPE
        url = SIS_IMPORTS_API.format(
            self._canvas_account_id) + ".json{}".format(self._params(params))
        headers = {"Content-Type": "text/csv"}

        return SISImportModel(data=self._post_resource(url, headers, csv))

def import_str ( self , csv , params = { } ) : if not self . _canvas_account_id : raise MissingAccountID ( ) params [ "import_type" ] = SISImportModel . CSV_IMPORT_TYPE url = SIS_IMPORTS_API . format ( self . _canvas_account_id ) + ".json{}" . format ( self . _params ( params ) ) headers = { "Content-Type" : "text/csv" } return SISImportModel ( data = self . _post_resource ( url , headers , csv ) )


def import_dir(self, dir_path, params={}):
        """
        Imports a directory of CSV files.

        https://canvas.instructure.com/doc/api/sis_imports.html#method.sis_imports_api.create
        """
        if not self._canvas_account_id:
            raise MissingAccountID()

        body = self._build_archive(dir_path)
        params["import_type"] = SISImportModel.CSV_IMPORT_TYPE
        url = SIS_IMPORTS_API.format(
            self._canvas_account_id) + ".json{}".format(self._params(params))
        headers = {"Content-Type": "application/zip"}

        return SISImportModel(data=self._post_resource(url, headers, body))

def import_dir ( self , dir_path , params = { } ) : if not self . _canvas_account_id : raise MissingAccountID ( ) body = self . _build_archive ( dir_path ) params [ "import_type" ] = SISImportModel . CSV_IMPORT_TYPE url = SIS_IMPORTS_API . format ( self . _canvas_account_id ) + ".json{}" . format ( self . _params ( params ) ) headers = { "Content-Type" : "application/zip" } return SISImportModel ( data = self . _post_resource ( url , headers , body ) )


def get_import_status(self, sis_import):
        """
        Get the status of an already created SIS import.

        https://canvas.instructure.com/doc/api/sis_imports.html#method.sis_imports_api.show
        """
        if not self._canvas_account_id:
            raise MissingAccountID()

        url = SIS_IMPORTS_API.format(
            self._canvas_account_id) + "/{}.json".format(sis_import.import_id)

        return SISImportModel(data=self._get_resource(url))

def get_import_status ( self , sis_import ) : if not self . _canvas_account_id : raise MissingAccountID ( ) url = SIS_IMPORTS_API . format ( self . _canvas_account_id ) + "/{}.json" . format ( sis_import . import_id ) return SISImportModel ( data = self . _get_resource ( url ) )

Get the status of an already created SIS import .


def _build_archive(self, dir_path):
        """
        Creates a zip archive from files in path.
        """
        zip_path = os.path.join(dir_path, "import.zip")
        archive = zipfile.ZipFile(zip_path, "w")

        for filename in CSV_FILES:
            filepath = os.path.join(dir_path, filename)

            if os.path.exists(filepath):
                archive.write(filepath, filename, zipfile.ZIP_DEFLATED)

        archive.close()

        with open(zip_path, "rb") as f:
            body = f.read()

        return body

def _build_archive ( self , dir_path ) : zip_path = os . path . join ( dir_path , "import.zip" ) archive = zipfile . ZipFile ( zip_path , "w" ) for filename in CSV_FILES : filepath = os . path . join ( dir_path , filename ) if os . path . exists ( filepath ) : archive . write ( filepath , filename , zipfile . ZIP_DEFLATED ) archive . close ( ) with open ( zip_path , "rb" ) as f : body = f . read ( ) return body

Creates a zip archive from files in path .


def get_assignments(self, course_id):
        """
        List assignments for a given course

        https://canvas.instructure.com/doc/api/assignments.html#method.assignments_api.index
        """
        url = ASSIGNMENTS_API.format(course_id)
        data = self._get_resource(url)
        assignments = []
        for datum in data:
            assignments.append(Assignment(data=datum))
        return assignments

def get_assignments ( self , course_id ) : url = ASSIGNMENTS_API . format ( course_id ) data = self . _get_resource ( url ) assignments = [ ] for datum in data : assignments . append ( Assignment ( data = datum ) ) return assignments


def update_assignment(self, assignment):
        """
        Modify an existing assignment.

        https://canvas.instructure.com/doc/api/assignments.html#method.assignments_api.update
        """
        url = ASSIGNMENTS_API.format(assignment.course_id) + "/{}".format(
            assignment.assignment_id)

        data = self._put_resource(url, assignment.json_data())
        return Assignment(data=data)

def update_assignment ( self , assignment ) : url = ASSIGNMENTS_API . format ( assignment . course_id ) + "/{}" . format ( assignment . assignment_id ) data = self . _put_resource ( url , assignment . json_data ( ) ) return Assignment ( data = data )


def get_available_reports(self, account_id):
        """
        Returns the list of reports for the canvas account id.

        https://canvas.instructure.com/doc/api/account_reports.html#method.account_reports.available_reports
        """
        url = ACCOUNTS_API.format(account_id) + "/reports"

        report_types = []
        for datum in self._get_resource(url):
            report_types.append(ReportType(data=datum, account_id=account_id))
        return report_types

def get_available_reports ( self , account_id ) : url = ACCOUNTS_API . format ( account_id ) + "/reports" report_types = [ ] for datum in self . _get_resource ( url ) : report_types . append ( ReportType ( data = datum , account_id = account_id ) ) return report_types

Returns the list of reports for the canvas account id .