Instruction:
Can you implement a function in Python 3 that
sets the PB Id for this device.

Response:
def pb_id(self, pb_id: str):
        """Set the PB Id for this device."""
        # FIXME(BMo) instead of creating the object to check if the PB exists
        #            use a method on PB List?
        # ProcessingBlock(pb_id)
        self.set_state(DevState.ON)
        self._pb_id = pb_id


Instruction:
Explain what the following Python 3 code does
def pb_config(self):
        pb = ProcessingBlock(self._pb_id)
        return json.dumps(pb.config)

Response: Return the PB configuration.


Instruction:
Write a Python 3 function that can
get the current state timestamp.

Response:
def current_timestamp(self) -> datetime:
        """Get the current state timestamp."""
        timestamp = DB.get_hash_value(self._key, 'current_timestamp')
        return datetime_from_isoformat(timestamp)


Instruction:
Write a Python 3 function that can
get the target state timestamp.

Response:
def target_timestamp(self) -> datetime:
        """Get the target state timestamp."""
        timestamp = DB.get_hash_value(self._key, 'target_timestamp')
        return datetime_from_isoformat(timestamp)


Instruction:
Given the following Python 3 function, write the documentation
def update_target_state(self, value: str, force: bool = True) -> datetime:
        value = value.lower()
        if not force:
            current_state = self.current_state
            if current_state == 'unknown':
                raise RuntimeError("Unable to set target state when current "
                                   "state is 'unknown'")

            allowed_target_states = self._allowed_target_states[current_state]

            LOG.debug('Updating target state of %s to %s', self._id, value)

            if value not in allowed_target_states:
                raise ValueError("Invalid target state: '{}'. {} can be "
                                 "commanded to states: {}".
                                 format(value, current_state,
                                        allowed_target_states))

        return self._update_state('target', value)

Response: Set the target state of the object.


Instruction:
Can you implement a function in Python 3 that
updates the current state of the resource.

Response:
def update_current_state(self, value: str,
                             force: bool = False) -> datetime:
        """Update the current state.

        Args:
            value (str): New value for sdp state
            force (bool): If true, ignore allowed transitions

        Returns:
            datetime, update timestamp

        Raises:
            ValueError: If the specified current state is not allowed.

        """
        value = value.lower()
        if not force:
            current_state = self.current_state
            # IF the current state is unknown, it can be set to any of the
            # allowed states, otherwise only allow certain transitions.
            if current_state == 'unknown':
                allowed_transitions = self._allowed_states
            else:
                allowed_transitions = self._allowed_transitions[current_state]
                allowed_transitions.append(current_state)

            LOG.debug('Updating current state of %s to %s', self._id, value)

            if value not in allowed_transitions:
                raise ValueError("Invalid current state update: '{}'. '{}' "
                                 "can be transitioned to states: {}"
                                 .format(value, current_state,
                                         allowed_transitions))

        return self._update_state('current', value)


Instruction:
Make a summary of the following Python 3 code
def _initialise(self, initial_state: str = 'unknown') -> dict:
        initial_state = initial_state.lower()
        if initial_state != 'unknown' and \
                initial_state not in self._allowed_states:
            raise ValueError('Invalid initial state: {}'.format(initial_state))
        _initial_state = dict(
            current_state=initial_state,
            target_state=initial_state,
            current_timestamp=datetime.utcnow().isoformat(),
            target_timestamp=datetime.utcnow().isoformat())
        return _initial_state

Response: Return a dictionary used to initialise a state object.


Instruction:
Can you tell what is the following Python 3 function doing
def _update_state(self, state_type: str, value: str) -> datetime:
        timestamp = datetime.utcnow()
        field = '{}_state'.format(state_type)
        old_state = DB.get_hash_value(self._key, field)
        DB.set_hash_value(self._key, field, value, pipeline=True)
        DB.set_hash_value(self._key, '{}_timestamp'.format(state_type),
                          timestamp.isoformat(), pipeline=True)
        DB.execute()

        # Publish an event to notify subscribers of the change in state
        self.publish('{}_state_updated'.format(state_type),
                     event_data=dict(state=value, old_state=old_state))

        return timestamp

Response: Update the state of the current or target.


Instruction:
Create a Python 3 function for
converting allowed state transitions / target states to lowercase.

Response:
def _dict_lower(dictionary: dict):
        """Convert allowed state transitions / target states to lowercase."""
        return {key.lower(): [value.lower() for value in value]
                for key, value in dictionary.items()}


Instruction:
Make a summary of the following Python 3 code
def add_sched_block_instance(self, config_dict):
        # Get schema for validation
        schema = self._get_schema()
        LOG.debug('Adding SBI with config: %s', config_dict)

        # Validates the schema
        validate(config_dict, schema)

        # Add status field and value to the data
        updated_block = self._add_status(config_dict)

        # Splitting into different names and fields before
        # adding to the database
        scheduling_block_data, processing_block_data = \
            self._split_sched_block_instance(updated_block)

        # Adding Scheduling block instance with id
        name = "scheduling_block:" + updated_block["id"]
        self._db.set_specified_values(name, scheduling_block_data)

        # Add a event to the scheduling block event list to notify
        # of a new scheduling block being added to the db.
        self._db.push_event(self.scheduling_event_name,
                            updated_block["status"],
                            updated_block["id"])

        # Adding Processing block with id
        for value in processing_block_data:
            name = ("scheduling_block:" + updated_block["id"] +
                    ":processing_block:" + value['id'])
            self._db.set_specified_values(name, value)

            # Add a event to the processing block event list to notify
            # of a new processing block being added to the db.
            self._db.push_event(self.processing_event_name,
                                value["status"],
                                value["id"])

Response: Adds a Scheduling Block instance to the database.


Instruction:
Create a Python 3 function to
get unordered list of scheduling block ids

Response:
def get_sched_block_instance_ids(self):
        """Get unordered list of scheduling block ids"""

        # Initialise empty list
        scheduling_block_ids = []

        # Pattern used to search scheduling block ids
        pattern = 'scheduling_block:*'
        block_ids = self._db.get_ids(pattern)

        for block_id in block_ids:
            if 'processing_block' not in block_id:
                id_split = block_id.split(':')[-1]
                scheduling_block_ids.append(id_split)
        return sorted(scheduling_block_ids)


Instruction:
Write a Python 3 function that can
get list of processing block ids using the processing block id

Response:
def get_processing_block_ids(self):
        """Get list of processing block ids using the processing block id"""

        # Initialise empty list
        _processing_block_ids = []

        # Pattern used to search processing block ids
        pattern = '*:processing_block:*'
        block_ids = self._db.get_ids(pattern)

        for block_id in block_ids:
            id_split = block_id.split(':')[-1]
            _processing_block_ids.append(id_split)
        return sorted(_processing_block_ids)


Instruction:
Can you write a function in Python 3 where it
gets list of sub array ids

Response:
def get_sub_array_ids(self):
        """Get list of sub array ids"""

        # Initialise empty list
        _scheduling_block_ids = []
        _sub_array_ids = []

        for blocks_id in self.get_sched_block_instance_ids():
            _scheduling_block_ids.append(blocks_id)
        block_details = self.get_block_details(_scheduling_block_ids)
        for details in block_details:
            _sub_array_ids.append(details['sub_array_id'])
        _sub_array_ids = sorted(list(set(_sub_array_ids)))
        return _sub_array_ids


Instruction:
Implement a function in Python 3 to
get Scheduling Block Instance ID associated with sub array id

Response:
def get_sub_array_sbi_ids(self, sub_array_id):
        """Get Scheduling Block Instance ID associated with sub array id"""
        _ids = []
        sbi_ids = self.get_sched_block_instance_ids()
        for details in self.get_block_details(sbi_ids):
            if details['sub_array_id'] == sub_array_id:
                _ids.append(details['id'])
        return sorted(_ids)


Instruction:
How would you implement a function in Python 3 that
gets details of scheduling or processing block.

Response:
def get_block_details(self, block_ids):
        """Get details of scheduling or processing block

        Args:
            block_ids (list): List of block IDs
        """
        # Convert input to list if needed
        if not hasattr(block_ids, "__iter__"):
            block_ids = [block_ids]

        for _id in block_ids:
            block_key = self._db.get_block(_id)[0]
            block_data = self._db.get_all_field_value(block_key)
            # NOTE(BM) unfortunately this doesn't quite work for keys where \
            # the value is a python type (list, dict etc) \
            # The following hack works for now but is probably not infallible
            for key in block_data:
                for char in ['[', '{']:
                    if char in block_data[key]:
                        block_data[key] = ast.literal_eval(
                            str(block_data[key]))
            yield block_data


Instruction:
How would you code a function in Python 3 to
update the value of the given block id and field

Response:
def update_value(self, block_id, field, value):
        """"Update the value of the given block id and field"""
        block_name = self._db.get_block(block_id)
        for name in block_name:
            self._db.set_value(name, field, value)


Instruction:
Write a Python 3 function for
deleting the specified Scheduling Block Instance.

Response:
def delete_sched_block_instance(self, block_id):
        """Delete the specified Scheduling Block Instance.

        Removes the Scheduling Block Instance, and all Processing Blocks
        that belong to it from the database"""
        LOG.debug('Deleting SBI %s', block_id)

        scheduling_blocks = self._db.get_all_blocks(block_id)
        if not scheduling_blocks:
            raise RuntimeError('Scheduling block not found: {}'.
                               format(block_id))

        if scheduling_blocks:
            for blocks in scheduling_blocks:
                if "processing_block" not in blocks:
                    self._db.delete_block(blocks)
                else:
                    split_key = blocks.split(':')
                    self._db.delete_block(blocks)

                    # Add a event to the processing block event list to notify
                    # about deleting from the db
                    self._db.push_event(self.processing_event_name, "deleted",
                                        split_key[3])

            # Add a event to the scheduling block event list to notify
            # of a deleting a scheduling block from the db
            self._db.push_event(self.scheduling_event_name, "deleted",
                                block_id)


Instruction:
Create a Python 3 function for
deleting a processing block from the database.

Response:
def delete_processing_block(self, processing_block_id):
        """Delete Processing Block(s).

        Uses Processing Block IDs
        """
        LOG.debug("Deleting Processing Block %s ...", processing_block_id)
        processing_block = self._db.get_block(processing_block_id)
        if not processing_block:
            raise RuntimeError('Invalid Processing Block ID: {}'
                               .format(processing_block_id))

        for block in processing_block:
            if 'processing_block' in block:
                self._db.delete_block(block)

                # Remove processing block id from scheduling block id
                scheduling_block_id = block.split(':')
                scheduling_block_details = self.get_block_details(
                    [scheduling_block_id[1]])
                for block_details in scheduling_block_details:
                    block_list = block_details['processing_block_ids']
                    if processing_block_id in block_list:
                        block_list.remove(processing_block_id)
                    self.update_value(scheduling_block_id[1],
                                      'processing_block_ids', block_list)

                # Add a event to the processing block event list to notify
                # about deleting from the db
                self._db.push_event(self.processing_event_name, "deleted",
                                    id)


Instruction:
Given the following Python 3 function, write the documentation
def _get_schema():
        schema_path = os.path.join(os.path.dirname(__file__),
                                   'schema', 'scheduling_block_schema.json')
        with open(schema_path, 'r') as file:
            schema_data = file.read()
        schema = json.loads(schema_data)
        return schema

Response: Get the schema for validation


Instruction:
Create a Python 3 function to
split the scheduling block data into multiple names before adding to the configuration database

Response:
def _split_sched_block_instance(self, scheduling_block):
        """Split the scheduling block data into multiple names
        before adding to the configuration database"""

        # Initialise empty list
        _scheduling_block_data = {}
        _processing_block_data = {}
        _processing_block_id = []

        for block in scheduling_block:
            values = scheduling_block[block]

            if block != 'processing_blocks':
                _scheduling_block_data[block] = values
            else:
                # Check if there is a processing block that already exits in
                # the database
                processing_block_id = self.get_processing_block_ids()

                for value in values:
                    if value['id'] not in processing_block_id:
                        _processing_block_data = values
                    else:
                        raise Exception("Processing block already exits",
                                        value['id'])

        # Adding processing block id to the scheduling block list
        for block_id in _processing_block_data:
            _processing_block_id.append(block_id['id'])
        _scheduling_block_data['processing_block_ids'] = _processing_block_id

        return _scheduling_block_data, _processing_block_data


Instruction:
Given the following Python 3 function, write the documentation
def init_logger(logger_name='sip', log_level=None, p3_mode: bool = True,
                show_thread: bool = False, propagate: bool = False,
                show_log_origin=False):
    """Initialise the SIP logger.

    Attaches a stdout stream handler to the 'sip' logger. This will
    apply to all logger objects with a name prefixed by 'sip.'

    This function respects the 'SIP_LOG_LEVEL' environment variable to
    set the logging level.

    Args:
        logger_name (str, optional): Name of the logger object.
        log_level (str or int, optional): Logging level for the SIP logger.
        p3_mode (bool, optional): Print logging statements in a format that
            P3 can support.
        show_thread (bool, optional): Display the thread in the log message.
        propagate (bool, optional): Propagate settings to parent loggers.
        show_log_origin (boo, optional): If true show the origin
            (file, line no.) of log messages.

    """
    log = logging.getLogger(logger_name)
    log.propagate = propagate

    # Remove existing handlers (avoids duplicate messages)
    for handler in log.handlers:
        log.removeHandler(handler)

    _debug = '%(filename)s:%(lineno)d | ' if show_log_origin else ''

    # P3 mode is intended to work with the fluentd configuration on P3.
    # This has ms timestamp precision and uses '-' as a delimiter
    # between statements in the log file.
    if p3_mode:
        _prefix = '%(asctime)s - %(name)s - %(levelname)s'
        if show_thread:
            _format = '{} - %(threadName)s - {}%(message)s'\
                .format(_prefix, _debug)
        else:
            _format = '{} - {}%(message)s'.format(_prefix, _debug)
        formatter = logging.Formatter(_format)
        formatter.converter = time.gmtime
    # If not in P3 mode, the timestamp will be us precision and use '|'
    # as a separator.
    else:
        _prefix = '%(asctime)s | %(name)s | %(levelname)s'
        if show_thread:
            _format = '{} | %(threadName)s | {}%(message)s'\
                .format(_prefix, _debug)
        else:
            _format = '{} | {}%(message)s'.format(_prefix, _debug)
        formatter = SIPFormatter(_format, datefmt='%Y-%m-%dT%H:%M:%S.%fZ')

    handler = logging.StreamHandler(stream=sys.stdout)
    handler.setFormatter(formatter)
    log.addHandler(handler)

    # Set the logging level.
    if log_level:
        log.setLevel(log_level)
    else:
        log.setLevel(os.getenv('SIP_LOG_LEVEL', 'DEBUG'))

Response: Initialises the SIP logger.


Instruction:
Write a Python 3 function that can
disable output for the specified logger.

Response:
def disable_logger(logger_name: str, propagate: bool = False):
    """Disable output for the logger of the specified name."""
    log = logging.getLogger(logger_name)
    log.propagate = propagate
    for handler in log.handlers:
        log.removeHandler(handler)


Instruction:
How would you explain what the following Python 3 function does
def set_log_level(logger_name: str, log_level: str, propagate: bool = False):
    log = logging.getLogger(logger_name)
    log.propagate = propagate
    log.setLevel(log_level)

Response: Set the log level of the specified logger.


Instruction:
Here you have a function in Python 3, explain what it does
def formatTime(self, record, datefmt=None):
        _seconds_fraction = record.created - int(record.created)
        _datetime_utc = time.mktime(time.gmtime(record.created))
        _datetime_utc += _seconds_fraction
        _created = self.converter(_datetime_utc)

        if datefmt:
            time_string = _created.strftime(datefmt)
        else:
            time_string = _created.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
            time_string = "%s,%03d" % (time_string, record.msecs)
        return time_string

Response: Format the log timestamp.


Instruction:
Create a Python 3 function for
generating a SBI config JSON string.

Response:
def generate_sbi(index: int = None):
    """Generate a SBI config JSON string."""
    date = datetime.datetime.utcnow().strftime('%Y%m%d')
    if index is None:
        index = randint(0, 999)
    sbi_id = 'SBI-{}-sip-demo-{:03d}'.format(date, index)
    sb_id = 'SBI-{}-sip-demo-{:03d}'.format(date, index)
    pb_id = 'PB-{}-sip-demo-{:03d}'.format(date, index)
    print('* Generating SBI: %s, PB: %s' % (sb_id, pb_id))
    sbi = dict(
        id=sbi_id,
        version='1.0.0',
        scheduling_block=dict(
            id=sb_id,
            project='sip',
            programme_block='sip_demos'
        ),
        processing_blocks=[
            dict(
                id=pb_id,
                version='1.0.0',
                type='offline',
                priority=1,
                dependencies=[],
                resources_required=[],
                workflow=dict(
                    id='mock_workflow',
                    version='1.0.0',
                    parameters=dict(
                        stage1=dict(duration=30),
                        stage2=dict(duration=30),
                        stage3=dict(duration=30)
                    )
                )
            )
        ]
    )
    return sbi


Instruction:
Here you have a function in Python 3, explain what it does
def send(self, config, log, obs_id, beam_id):
        log.info('Starting Pulsar Data Transfer...')
        socket = self._ftp.transfercmd('STOR {0}_{1}'.format(obs_id, beam_id))
        socket.send(json.dumps(config).encode())
        socket.send(bytearray(1000 * 1000))

        # Overwrites the metadata name in the config dict
        # and re-sends the data to the receiver.
        config['metadata']['name'] = 'candidate_two'
        socket.send(json.dumps(config).encode())
        socket.send(bytearray(1000 * 1000))
        socket.close()
        log.info('Pulsar Data Transfer Completed...')

Response: Send the pulsar data to the server


Instruction:
Make a summary of the following Python 3 code
def get(block_id):
    _url = get_root_url()
    try:
        block = DB.get_block_details([block_id]).__next__()
        response = block

        response['links'] = {
            'self': '{}'.format(request.url),
            'list': '{}/processing-blocks'.format(_url),
            'home': '{}'.format(_url)
        }
        return block
    except IndexError as error:
        response = dict(message='Unable to GET Processing Block',
                        id='{}'.format(block_id),
                        error=error.__str__())
        response['links'] = {
            'list': '{}/processing-blocks'.format(_url),
            'home': '{}'.format(_url)
        }
        return response, HTTPStatus.NOT_FOUND

Response: Get a single Processing Block detail resource.


Instruction:
Implement a function in Python 3 to
delete a Processing Block

Response:
def delete(block_id):
    """Processing block detail resource."""
    _url = get_root_url()
    try:
        DB.delete_processing_block(block_id)
        response = dict(message='Deleted block',
                        id='{}'.format(block_id),
                        links=dict(list='{}/processing-blocks'.format(_url),
                                   home='{}'.format(_url)))
        return response, HTTPStatus.OK
    except RuntimeError as error:
        response = dict(error='Failed to delete Processing Block: {}'.
                        format(block_id),
                        reason=str(error),
                        links=dict(list='{}/processing-blocks'.format(_url),
                                   home='{}'.format(_url)))
        return response, HTTPStatus.OK


Instruction:
Create a Python 3 function to
configure an SBI for this subarray.

Response:
def configure(self, sbi_config: str):
        """Configure an SBI for this subarray.

        Args:
            sbi_config (str): SBI configuration JSON

        Returns:
            str,

        """
        # print(sbi_config)
        config_dict = json.loads(sbi_config)
        self.debug_stream('SBI configuration:\n%s',
                          json.dumps(config_dict, indent=2))
        try:
            sbi = Subarray(self.get_name()).configure_sbi(config_dict)
        except jsonschema.exceptions.ValidationError as error:
            return json.dumps(dict(path=error.absolute_path.__str__(),
                                   schema_path=error.schema_path.__str__(),
                                   message=error.message), indent=2)
        except RuntimeError as error:
            return json.dumps(dict(error=str(error)), indent=2)
        return 'Accepted SBI: {}'.format(sbi.id)


Instruction:
Make a summary of the following Python 3 code
def processing_blocks(self):
        sbi_ids = Subarray(self.get_name()).sbi_ids
        pbs = []
        for sbi_id in sbi_ids:
            sbi = SchedulingBlockInstance(sbi_id)
            pbs.append(sbi.processing_block_ids)
        return 'PB', pbs

Response: Return list of PBs associated with the subarray.


Instruction:
Write a Python 3 function for
returning a datetime object from an ISO - 8601 string.

Response:
def datetime_from_isoformat(value: str):
    """Return a datetime object from an isoformat string.

    Args:
        value (str): Datetime string in isoformat.

    """
    if sys.version_info >= (3, 7):
        return datetime.fromisoformat(value)

    return datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f')


Instruction:
How would you implement a function in Python 3 that
initializes the device proxy.

Response:
def init_device(self):
        """Device constructor."""
        Device.init_device(self)

        # Add anything here that has to be done before the device is set to
        # its ON state.

        self._set_master_state('on')
        self._devProxy = DeviceProxy(self.get_name())


Instruction:
Create a Python 3 function to
run for each command.

Response:
def always_executed_hook(self):
        """Run for each command."""
        _logT = self._devProxy.get_logging_target()
        if 'device::sip_sdp_logger' not in _logT:
            try:
                self._devProxy.add_logging_target('device::sip_sdp/elt/logger')
                self.info_stream("Test of Tango logging from "
                                 "'tc_tango_master'")

            except Exception as e:
                LOG.debug('Failed to setup Tango logging %s', e )


Instruction:
Can you tell what is the following Python 3 function doing
def configure(self, value):

        # Only accept new SBIs if the SDP is on.
        if self._sdp_state.current_state != 'on':
            raise RuntimeWarning('Unable to configure SBIs unless SDP is '
                                 '\'on\'.')

        # Check that the new SBI is not already registered.
        sbi_config_dict = json.loads(value)
        sbi_list = SchedulingBlockInstanceList()
        LOG.info('SBIs before: %s', sbi_list.active)
        if sbi_config_dict.get('id') in sbi_list.active:
            raise RuntimeWarning('Unable to add SBI with ID {}, an SBI with '
                                 'this ID is already registered with SDP!'
                                 .format(sbi_config_dict.get('id')))

        # Add the SBI to the dictionary.
        LOG.info('Scheduling offline SBI! Config:\n%s', value)
        sbi = SchedulingBlockInstance.from_config(sbi_config_dict)
        LOG.info('SBIs after: %s', sbi_list.active)

        sbi_pb_ids = sbi.processing_block_ids
        LOG.info('SBI "%s" contains PBs: %s', sbi.id, sbi_pb_ids)
        # pb_list = ProcessingBlockList()
        # LOG.info('Active PBs: %s', pb_list.active)

        # Get the list and number of Tango PB devices
        tango_db = Database()
        pb_device_class = "ProcessingBlockDevice"
        pb_device_server_instance = "processing_block_ds/1"
        pb_devices = tango_db.get_device_name(pb_device_server_instance,
                                              pb_device_class)
        LOG.info('Number of PB devices in the pool = %d', len(pb_devices))

        # Get a PB device which has not been assigned.
        for pb_id in sbi_pb_ids:
            for pb_device_name in pb_devices:
                device = DeviceProxy(pb_device_name)

                if not device.pb_id:
                    LOG.info('Assigning PB device = %s to PB id = %s',
                             pb_device_name, pb_id)
                    # Set the device attribute 'pb_id' to the processing block
                    # id it is tracking.
                    device.pb_id = pb_id
                    break

Response: Configure an offline only SBI with SDP.


Instruction:
Write a Python 3 script for
getting the Service state object for the specified id.

Response:
def _get_service_state(service_id: str):
        """Get the Service state object for the specified id."""
        LOG.debug('Getting state of service %s', service_id)
        services = get_service_id_list()
        service_ids = [s for s in services if service_id in s]
        if len(service_ids) != 1:
            return 'Service not found! services = {}'.format(str(services))
        subsystem, name, version = service_ids[0].split(':')
        return ServiceState(subsystem, name, version)


Instruction:
Write a Python 3 function that can
get the state of a SDP service.

Response:
def get_current_service_state(self, service_id: str):
        """Get the state of a SDP service."""
        state = self._get_service_state(service_id)
        return state.current_state


Instruction:
Make a summary of the following Python 3 code
def get_target_service_state(self, service_id: str):
        state = self._get_service_state(service_id)
        return state.target_state

Response: Get the state of a SDP service.


Instruction:
Write a Python 3 function that can
return a list of allowed target states for the current state.

Response:
def allowed_target_sdp_states(self):
        """Return a list of allowed target states for the current state."""
        _current_state = self._sdp_state.current_state
        _allowed_target_states = self._sdp_state.allowed_target_states[
            _current_state]
        return json.dumps(dict(allowed_target_sdp_states=
                               _allowed_target_states))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def target_sdp_state(self, state):
        LOG.info('Setting SDP target state to %s', state)
        if self._sdp_state.current_state == state:
            LOG.info('Target state ignored, SDP is already "%s"!', state)
        if state == 'on':
            self.set_state(DevState.ON)
        if state == 'off':
            self.set_state(DevState.OFF)
        if state == 'standby':
            self.set_state(DevState.STANDBY)
        if state == 'disable':
            self.set_state(DevState.DISABLE)
        self._sdp_state.update_target_state(state)

Response: Update the target state of the SDP.


Instruction:
Can you implement a function in Python 3 that
returns a JSON dict encoding the SBIs known to SDP.

Response:
def scheduling_block_instances(self):
        """Return the a JSON dict encoding the SBIs known to SDP."""
        # TODO(BMo) change this to a pipe?
        sbi_list = SchedulingBlockInstanceList()
        return json.dumps(dict(active=sbi_list.active,
                               completed=sbi_list.completed,
                               aborted=sbi_list.aborted))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def processing_blocks(self):
        pb_list = ProcessingBlockList()
        # TODO(BMo) realtime, offline etc.
        return json.dumps(dict(active=pb_list.active,
                               completed=pb_list.completed,
                               aborted=pb_list.aborted))

Response: Return a JSON dict encoding the PBs known to SDP.


Instruction:
Create a Python 3 function to
get list of processing block devices.

Response:
def processing_block_devices(self):
        """Get list of processing block devices."""
        # Get the list and number of Tango PB devices
        tango_db = Database()
        pb_device_class = "ProcessingBlockDevice"
        pb_device_server_instance = "processing_block_ds/1"
        pb_devices = tango_db.get_device_name(pb_device_server_instance,
                                              pb_device_class)
        LOG.info('Number of PB devices in the pool = %d', len(pb_devices))

        pb_device_map = []
        for pb_device_name in pb_devices:
            device = DeviceProxy(pb_device_name)
            if device.pb_id:
                LOG.info('%s %s', pb_device_name, device.pb_id)
                pb_device_map.append((pb_device_name, device.pb_id))

        return str(pb_device_map)


Instruction:
Given the following Python 3 function, write the documentation
def _set_master_state(self, state):
        if state == 'init':
            self._service_state.update_current_state('init', force=True)
            self.set_state(DevState.INIT)

        elif state == 'on':
            self.set_state(DevState.ON)
            self._service_state.update_current_state('on')

Response: Set the state of the SDPMaster.


Instruction:
Can you write a function in Python 3 where it
adds any missing SBI workflow definitions as placeholders.

Response:
def add_workflow_definitions(sbi_config: dict):
    """Add any missing SBI workflow definitions as placeholders.

    This is a utility function used in testing and adds mock / test workflow
    definitions to the database for workflows defined in the specified
    SBI config.

    Args:
        sbi_config (dict): SBI configuration dictionary.

    """
    registered_workflows = []
    for i in range(len(sbi_config['processing_blocks'])):
        workflow_config = sbi_config['processing_blocks'][i]['workflow']
        workflow_name = '{}:{}'.format(workflow_config['id'],
                                       workflow_config['version'])
        if workflow_name in registered_workflows:
            continue
        workflow_definition = dict(
            id=workflow_config['id'],
            version=workflow_config['version'],
            stages=[]
        )
        key = "workflow_definitions:{}:{}".format(workflow_config['id'],
                                                  workflow_config['version'])
        DB.save_dict(key, workflow_definition, hierarchical=False)
        registered_workflows.append(workflow_name)


Instruction:
Make a summary of the following Python 3 code
def generate_version(max_major: int = 1, max_minor: int = 7,
                     max_patch: int = 15) -> str:
    """Select a random version.

    Args:
        max_major (int, optional) maximum major version
        max_minor (int, optional) maximum minor version
        max_patch (int, optional) maximum patch version

    Returns:
        str, Version String

    """
    major = randint(0, max_major)
    minor = randint(0, max_minor)
    patch = randint(0, max_patch)
    return '{:d}.{:d}.{:d}'.format(major, minor, patch)

Response: Select a random version.


Instruction:
Write a Python 3 function that can
generate a SBI Scheduling Block data object.

Response:
def generate_sb(date: datetime.datetime, project: str,
                programme_block: str) -> dict:
    """Generate a Scheduling Block data object.

    Args:
        date (datetime.datetime): UTC date of the SBI
        project (str): Project Name
        programme_block (str): Programme

    Returns:
        str, Scheduling Block Instance (SBI) ID.

    """
    date = date.strftime('%Y%m%d')
    instance_id = randint(0, 9999)
    sb_id = 'SB-{}-{}-{:04d}'.format(date, project, instance_id)
    return dict(id=sb_id, project=project, programme_block=programme_block)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def generate_pb_config(pb_id: str,
                       pb_config: dict = None,
                       workflow_config: dict = None) -> dict:
    """Generate a PB configuration dictionary.

    Args:
        pb_id (str): Processing Block Id
        pb_config (dict, optional) PB configuration.
        workflow_config (dict, optional): Workflow configuration

    Returns:
        dict, PB configuration dictionary.

    """
    if workflow_config is None:
        workflow_config = dict()
    if pb_config is None:
        pb_config = dict()
    pb_type = pb_config.get('type', choice(PB_TYPES))
    workflow_id = workflow_config.get('id')
    if workflow_id is None:
        if pb_type == 'offline':
            workflow_id = choice(OFFLINE_WORKFLOWS)
        else:
            workflow_id = choice(REALTIME_WORKFLOWS)
    workflow_version = workflow_config.get('version', generate_version())
    workflow_parameters = workflow_config.get('parameters', dict())
    pb_data = dict(
        id=pb_id,
        version=__pb_version__,
        type=pb_type,
        priority=pb_config.get('priority', randint(0, 10)),
        dependencies=pb_config.get('dependencies', []),
        resources_required=pb_config.get('resources_required', []),
        workflow=dict(
            id=workflow_id,
            version=workflow_version,
            parameters=workflow_parameters
        )
    )
    return pb_data

Response: Generate a PB configuration dictionary.


Instruction:
Here you have a function in Python 3, explain what it does
def generate_sbi_config(num_pbs: int = 3, project: str = 'sip',
                        programme_block: str = 'sip_demos',
                        pb_config: Union[dict, List[dict]] = None,
                        workflow_config:
                        Union[dict, List[dict]] = None,
                        register_workflows=False) -> dict:
    """Generate a SBI configuration dictionary.

    Args:
        num_pbs (int, optional): Number of Processing Blocks (default = 3)
        project (str, optional): Project to associate the SBI with.
        programme_block (str, optional): SBI programme block
        pb_config (dict, List[dict], optional): PB configuration
        workflow_config (dict, List[dict], optional): Workflow configuration
        register_workflows (bool, optional): If true also register workflows.

    Returns:
        dict, SBI configuration dictionary

    """
    if isinstance(workflow_config, dict):
        workflow_config = [workflow_config]
    if isinstance(pb_config, dict):
        pb_config = [pb_config]
    utc_now = datetime.datetime.utcnow()
    pb_list = []
    for i in range(num_pbs):
        pb_id = ProcessingBlock.get_id(utc_now)
        if workflow_config is not None:
            _workflow_config = workflow_config[i]
        else:
            _workflow_config = None
        if pb_config is not None:
            _pb_config = pb_config[i]
        else:
            _pb_config = None
        pb_dict = generate_pb_config(pb_id, _pb_config, _workflow_config)
        pb_list.append(pb_dict)
    sbi_config = dict(
        id=SchedulingBlockInstance.get_id(utc_now, project),
        version=__sbi_version__,
        scheduling_block=generate_sb(utc_now, project, programme_block),
        processing_blocks=pb_list
    )
    if register_workflows:
        add_workflow_definitions(sbi_config)
    return sbi_config

Response: Generate a SBI configuration dictionary.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def generate_sbi_json(num_pbs: int = 3, project: str = 'sip',
                      programme_block: str = 'sip_demos',
                      pb_config: Union[dict, List[dict]] = None,
                      workflow_config:
                      Union[dict, List[dict]] = None,
                      register_workflows=True) -> str:
    """Return a JSON string used to configure an SBI."""
    return json.dumps(generate_sbi_config(num_pbs, project, programme_block,
                                          pb_config,
                                          workflow_config, register_workflows))

Response: Generates a JSON string used to configure an SBI.


Instruction:
Here you have a function in Python 3, explain what it does
def log(self, argin):
        #
        # Tango Manual Appendix 9 gives the format
        # argin[0] = millisecond Unix timestamp
        # argin[1] = log level
        # argin[2] = the source log device name
        # argin[3] = the log message
        # argin[4] = Not used - reserved
        # argin[5] = thread identifier of originating message

        tm = datetime.datetime.fromtimestamp(float(argin[0])/1000.)
        fmt = "%Y-%m-%d %H:%M:%S"
        message = "TANGO Log message - {} - {} {} {}".format(
            tm.strftime(fmt), argin[1], argin[2], argin[3])
        LOG.info(message)

Response: Log a command for the SDP STango ubsystem devices.


Instruction:
Write a Python 3 function that can
get the Scheduling block detail resource.

Response:
def get(block_id):
    """Scheduling block detail resource."""
    try:
        sbi_details = DB.get_block_details([block_id]).__next__()
        sbi_details['processing_blocks'] = []
        pb_ids = sbi_details['processing_block_ids']
        for pb_details in DB.get_block_details(pb_ids):
            sbi_details['processing_blocks'].append(pb_details)
        del sbi_details['processing_block_ids']
        response = sbi_details
        _url = get_root_url()
        response['links'] = {
            'scheduling-blocks': '{}/scheduling-blocks'.format(_url),
            'home': '{}'.format(_url)
        }
        return sbi_details, HTTPStatus.OK

    except IndexError:
        return {'error': 'specified block id not found {}'.format(block_id)}, \
               HTTPStatus.NOT_FOUND


Instruction:
Can you write a function in Python 3 where it
deletes the Scheduling block instance with the given ID.

Response:
def delete(block_id):
    """Scheduling block detail resource."""
    _url = get_root_url()
    LOG.debug('Requested delete of SBI %s', block_id)
    try:
        DB.delete_sched_block_instance(block_id)
        response = dict(message='Deleted block: _id = {}'.format(block_id))
        response['_links'] = {
            'list': '{}/scheduling-blocks'.format(_url)
        }
        return response, HTTPStatus.OK
    except RuntimeError as error:
        return dict(error=str(error)), HTTPStatus.BAD_REQUEST


Instruction:
Can you create a Python 3 function that
generates Scheduling Block instance IDs

Response:
def _scheduling_block_ids(num_blocks, start_id, project):
    """Generate Scheduling Block instance ID"""
    for i in range(num_blocks):
        _root = '{}-{}'.format(strftime("%Y%m%d", gmtime()), project)
        yield '{}-sb{:03d}'.format(_root, i + start_id), \
              '{}-sbi{:03d}'.format(_root, i + start_id)


Instruction:
Create a Python 3 function for
generating a number of Processing Blocks

Response:
def _generate_processing_blocks(start_id, min_blocks=0, max_blocks=4):
    """Generate a number of Processing Blocks"""
    processing_blocks = []
    num_blocks = random.randint(min_blocks, max_blocks)
    for i in range(start_id, start_id + num_blocks):
        _id = 'sip-pb{:03d}'.format(i)
        block = dict(id=_id, resources_requirement={}, workflow={})
        processing_blocks.append(block)
    return processing_blocks


Instruction:
Can you generate the documentation for the following Python 3 function
def _scheduling_block_config(num_blocks=5, start_sbi_id=0, start_pb_id=0,
                             project='sip'):
    """Return a Scheduling Block Configuration dictionary"""
    pb_id = start_pb_id
    for sb_id, sbi_id in _scheduling_block_ids(num_blocks, start_sbi_id,
                                               project):
        sub_array_id = 'subarray-{:02d}'.format(random.choice(range(5)))
        config = dict(id=sbi_id,
                      sched_block_id=sb_id,
                      sub_array_id=sub_array_id,
                      processing_blocks=_generate_processing_blocks(pb_id))
        pb_id += len(config['processing_blocks'])
        yield config

Response: Generate a Scheduling Block Configuration dictionary


Instruction:
Here you have a function in Python 3, explain what it does
def add_scheduling_blocks(num_blocks, clear=True):
    db_client = ConfigDb()
    if clear:
        LOG.info('Resetting database ...')
        db_client.clear()
        start_sbi_id = 0
        start_pb_id = 0
    else:
        start_sbi_id = len(db_client.get_sched_block_instance_ids())
        start_pb_id = len(db_client.get_processing_block_ids())

    LOG.info("Adding %i SBIs to the db", num_blocks)
    for config in _scheduling_block_config(num_blocks, start_sbi_id,
                                           start_pb_id):
        LOG.info('Creating SBI %s with %i PBs.', config['id'],
                 len(config['processing_blocks']))
        db_client.add_sched_block_instance(config)

Response: Add a number of scheduling blocks to the db.


Instruction:
Here you have a function in Python 3, explain what it does
def main(args=None, **kwargs):
    LOG.info('Starting SDP PB devices.')
    return run([ProcessingBlockDevice], verbose=True, msg_stream=sys.stdout,
               args=args, **kwargs)

Response: Start the Processing Block device server.


Instruction:
Can you create a Python 3 function that
generates a Processing Block Instance ID.

Response:
def get_id(date: datetime.datetime) -> str:
        """Generate a Processing Block (PB) Instance ID.

        Args:
            date (datetime.datetime): UTC date of the PB

        Returns:
            str, Processing Block ID

        """
        date = date.strftime('%Y%m%d')
        return 'PB-{}-{}-{:03d}'.format(date, 'sip', randint(0, 100))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def dependencies(self) -> List[Dependency]:
        dependencies_str = DB.get_hash_value(self.key, 'dependencies')
        dependencies = []
        for dependency in ast.literal_eval(dependencies_str):
            dependencies.append(Dependency(dependency))
        return dependencies

Response: Return the PB dependencies.


Instruction:
How would you code a function in Python 3 to
return list of resources assigned to the PB.

Response:
def resources_assigned(self) -> List[Resource]:
        """Return list of resources assigned to the PB."""
        resources_str = DB.get_hash_value(self.key, 'resources_assigned')
        resources_assigned = []
        for resource in ast.literal_eval(resources_str):
            resources_assigned.append(Resource(resource))
        return resources_assigned


Instruction:
Given the following Python 3 function, write the documentation
def workflow_stages(self) -> List[WorkflowStage]:
        workflow_stages = []
        stages = DB.get_hash_value(self.key, 'workflow_stages')
        for index in range(len(ast.literal_eval(stages))):
            workflow_stages.append(WorkflowStage(self.id, index))
        return workflow_stages

Response: Return list of workflow stages.


Instruction:
Can you tell what is the following Python 3 function doing
def add_assigned_resource(self, resource_type: str,
                              value: Union[str, int, float, bool],
                              parameters: dict = None):
        """Add assigned resource to the processing block.

        Args:
            resource_type (str): Resource type
            value: Resource value
            parameters (dict, optional): Parameters specific to the resource

        """
        if parameters is None:
            parameters = dict()
        resources = DB.get_hash_value(self.key, 'resources_assigned')
        resources = ast.literal_eval(resources)
        resources.append(dict(type=resource_type, value=value,
                              parameters=parameters))
        DB.set_hash_value(self.key, 'resources_assigned', resources)

Response: Adds assigned resource to the processing block.


Instruction:
Implement a function in Python 3 to
remove assigned resources from the processing block.

Response:
def remove_assigned_resource(self, resource_type: str,
                                 value: Union[str, int, float, bool] = None,
                                 parameters: dict = None):
        """Remove assigned resources from the processing block.

        All matching resources will be removed. If only type is specified
        all resources of the specified type will be removed.
        If value and/or parameters are specified they will be used
        for matching the resource to remove.

        Args:
            resource_type (str): Resource type
            value: Resource value
            parameters (dict, optional): Parameters specific to the resource

        """
        resources = DB.get_hash_value(self.key, 'resources_assigned')
        resources = ast.literal_eval(resources)
        new_resources = []
        for resource in resources:
            if resource['type'] != resource_type:
                new_resources.append(resource)
            elif value is not None and resource['value'] != value:
                new_resources.append(resource)
            elif parameters is not None and \
                    resource['parameters'] != parameters:
                new_resources.append(resource)
        DB.set_hash_value(self.key, 'resources_assigned', new_resources)


Instruction:
Write a Python 3 function that can
update the updated timestamp.

Response:
def _mark_updated(self):
        """Update the updated timestamp."""
        timestamp = datetime.datetime.utcnow().isoformat()
        DB.set_hash_value(self.key, 'updated', timestamp)


Instruction:
Make a summary of the following Python 3 code
def get():
    _url = get_root_url()
    LOG.debug('GET Sub array list')

    sub_array_ids = sorted(DB.get_sub_array_ids())

    response = dict(sub_arrays=[])
    for array_id in sub_array_ids:
        array_summary = dict(sub_arrary_id=array_id)
        block_ids = DB.get_sub_array_sbi_ids(array_id)
        LOG.debug('Subarray IDs: %s', array_id)
        LOG.debug('SBI IDs: %s', block_ids)
        array_summary['num_scheduling_blocks'] = len(block_ids)
        array_summary['links'] = {
            'detail': '{}/sub-array/{}'.format(_url, array_id)
        }
        response['sub_arrays'].append(array_summary)
    response['links'] = dict(self=request.url, home=_url)
    return response, status.HTTP_200_OK

Response: Subarray list. This method will list all sub - arrays known to SDP.


Instruction:
Create a Python 3 function for
setting the subarray parameters.

Response:
def set_parameters(self, parameters_dict):
        """Set the subarray parameters.

        Args:
            parameters_dict (dict): Dictionary of Subarray parameters
        """
        DB.set_hash_value(self._key, 'parameters', parameters_dict)
        self.publish("parameters_updated")


Instruction:
Can you generate the documentation for the following Python 3 function
def sbi_ids(self) -> List[str]:
        return ast.literal_eval(DB.get_hash_value(self._key, 'sbi_ids'))

Response: Get the list of SBI Ids associated with this subarray.


Instruction:
Implement a Python 3 function for
adding a new SBI to the database associated with this subarray.

Response:
def configure_sbi(self, sbi_config: dict, schema_path: str = None):
        """Add a new SBI to the database associated with this subarray.

        Args:
            sbi_config (dict): SBI configuration.
            schema_path (str, optional): Path to the SBI config schema.

        """
        if not self.active:
            raise RuntimeError("Unable to add SBIs to inactive subarray!")
        sbi_config['subarray_id'] = self._id
        sbi = SchedulingBlockInstance.from_config(sbi_config, schema_path)
        self._add_sbi_id(sbi_config['id'])
        return sbi


Instruction:
Here you have a function in Python 3, explain what it does
def abort(self):
        for sbi_id in self.sbi_ids:
            sbi = SchedulingBlockInstance(sbi_id)
            sbi.abort()
        self.set_state('ABORTED')

Response: Abort all SBIs associated with the subarray.


Instruction:
Create a Python 3 function for
removing an SBI Identifier from the SBI cache.

Response:
def remove_sbi_id(self, sbi_id):
        """Remove an SBI Identifier."""
        sbi_ids = self.sbi_ids
        sbi_ids.remove(sbi_id)
        DB.set_hash_value(self._key, 'sbi_ids', sbi_ids)


Instruction:
Can you create a Python 3 function that
adds a SBI Identifier.

Response:
def _add_sbi_id(self, sbi_id):
        """Add a SBI Identifier."""
        sbi_ids = self.sbi_ids
        sbi_ids.append(sbi_id)
        DB.set_hash_value(self._key, 'sbi_ids', sbi_ids)


Instruction:
Can you generate the documentation for the following Python 3 function
def get(self) -> Union[Event, None]:
        message = self._queue.get_message()
        if message and message['type'] == 'message':
            event_id = DB.get_event(self._pub_key, self._processed_key)
            event_data_str = DB.get_hash_value(self._data_key, event_id)
            event_dict = ast.literal_eval(event_data_str)
            event_dict['id'] = event_id
            event_dict['subscriber'] = self._subscriber
            return Event.from_config(event_dict)
        return None

Response: Get the latest event from the queue.


Instruction:
Here you have a function in Python 3, explain what it does
def get_published_events(self, process=True) -> List[Event]:
        LOG.debug('Getting published events (%s)', self._pub_key)
        if process:
            LOG.debug('Marking returned published events as processed.')
            DB.watch(self._pub_key, pipeline=True)
            event_ids = DB.get_list(self._pub_key, pipeline=True)
            if event_ids:
                DB.delete(self._pub_key, pipeline=True)
                DB.append_to_list(self._processed_key, *event_ids,
                                  pipeline=True)
            DB.execute()
        else:
            event_ids = DB.get_list(self._pub_key)

        events = []
        for event_id in event_ids[::-1]:
            event_str = DB.get_hash_value(self._data_key, event_id)
            event_dict = ast.literal_eval(event_str)
            event_dict['id'] = event_id
            event = Event.from_config(event_dict)
            LOG.debug('Loaded event: %s (%s)', event.id, event.type)
            events.append(event)
        return events

Response: Get a list of published events.


Instruction:
Implement a function in Python 3 to
get all processed events.

Response:
def get_processed_events(self) -> List[Event]:
        """Get all processed events.

        This method is intended to be used to recover events stuck in the
        processed state which could happen if an event handling processing
        an processed event goes down before completing the event processing.

        Returns:
            list[Events], list of event objects.

        """
        event_ids = DB.get_list(self._processed_key)
        events = []
        for event_id in event_ids:
            event_str = DB.get_hash_value(self._data_key, event_id)
            event_dict = ast.literal_eval(event_str)
            event_dict['id'] = event_id
            event_dict['subscriber'] = self._subscriber
            events.append(Event.from_config(event_dict))
        return events


Instruction:
Can you generate a brief explanation for the following Python 3 code
def complete_event(self, event_id: str):
        event_ids = DB.get_list(self._processed_key)
        if event_id not in event_ids:
            raise KeyError('Unable to complete event. Event {} has not been '
                           'processed (ie. it is not in the processed '
                           'list).'.format(event_id))
        DB.remove_from_list(self._processed_key, event_id, pipeline=True)
        key = _keys.completed_events(self._object_type, self._subscriber)
        DB.append_to_list(key, event_id, pipeline=True)
        DB.execute()

Response: Complete the specified event.


Instruction:
Can you create a Python 3 function that
adds a workflow definition to the Configuration Database.

Response:
def add(workflow_definition: dict, templates_root: str):
    """Add a workflow definition to the Configuration Database.

    Templates are expected to be found in a directory tree with the following
    structure:

        - workflow_id:
            |- workflow_version
                |- stage_id
                    |- stage_version
                        |- <templates>

    Args:
        workflow_definition (dict): Workflow definition.
        templates_root (str): Workflow templates root path

    """
    schema_path = join(dirname(__file__), 'schema', 'workflow_definition.json')
    with open(schema_path, 'r') as file:
        schema = json.loads(file.read())

    jsonschema.validate(workflow_definition, schema)

    _id = workflow_definition['id']
    _version = workflow_definition['version']
    _load_templates(workflow_definition, templates_root)

    workflow_id = workflow_definition['id']
    version = workflow_definition['version']
    name = "workflow_definitions:{}:{}".format(workflow_id, version)

    if DB.get_keys(name):
        raise KeyError('Workflow definition already exists: {}'.format(name))

    # DB.set_hash_values(name, workflow_definition)
    DB.save_dict(name, workflow_definition, hierarchical=False)


Instruction:
Can you implement a function in Python 3 that
registers an empty workflow definition in the database.

Response:
def register(workflow_id, workflow_version):
    """Register an (empty) workflow definition in the database."""
    name = "workflow_definitions:{}:{}".format(workflow_id, workflow_version)
    workflow_definition = dict(id=workflow_id, version=workflow_version,
                               stages=[])
    # DB.set_hash_values(name, workflow_definition)
    DB.save_dict(name, workflow_definition, hierarchical=False)


Instruction:
How would you implement a function in Python 3 that
deletes all the workflow_id and version from the database.

Response:
def delete(workflow_id: str = None, workflow_version: str = None):
    """Delete workflow definitions.

    Args:
        workflow_id (str, optional): Optional workflow identifier
        workflow_version (str, optional): Optional workflow identifier version

    If workflow_id and workflow_version are None, delete all workflow
    definitions.

    """
    if workflow_id is None and workflow_version is None:
        keys = DB.get_keys("workflow_definitions:*")
        DB.delete(*keys)
    elif workflow_id is not None and workflow_version is None:
        keys = DB.get_keys("workflow_definitions:{}:*".format(workflow_id))
        DB.delete(*keys)
    elif workflow_id is None and workflow_version is not None:
        keys = DB.get_keys("workflow_definitions:*:{}"
                           .format(workflow_version))
        DB.delete(*keys)
    else:
        name = "workflow_definitions:{}:{}".format(workflow_id,
                                                   workflow_version)
        DB.delete(name)


Instruction:
How would you implement a function in Python 3 that
gets a workflow definition from the Configuration Database.

Response:
def get_workflow(workflow_id: str, workflow_version: str) -> dict:
    """Get a workflow definition from the Configuration Database.

    Args:
        workflow_id (str): Workflow identifier
        workflow_version (str): Workflow version

    Returns:
        dict, Workflow definition dictionary

    """
    name = "workflow_definitions:{}:{}".format(workflow_id, workflow_version)
    workflow = DB.get_hash_dict(name)
    workflow['stages'] = ast.literal_eval(workflow['stages'])
    return workflow


Instruction:
Write a Python 3 script for
getting dict of ALL known workflow definitions. Returns list of dictionaries

Response:
def get_workflows() -> dict:
    """Get dict of ALL known workflow definitions.

    Returns
        list[dict]

    """
    keys = DB.get_keys("workflow_definitions:*")
    known_workflows = dict()
    for key in keys:
        values = key.split(':')
        if values[1] not in known_workflows:
            known_workflows[values[1]] = list()
        known_workflows[values[1]].append(values[2])

    return known_workflows


Instruction:
Can you implement a function in Python 3 that
deletes PBs devices from the Tango database.

Response:
def delete_pb_devices():
    """Delete PBs devices from the Tango database."""
    parser = argparse.ArgumentParser(description='Register PB devices.')
    parser.add_argument('num_pb', type=int,
                        help='Number of PBs devices to register.')
    args = parser.parse_args()

    log = logging.getLogger('sip.tango_control.subarray')
    tango_db = Database()
    log.info("Deleting PB devices:")
    for index in range(args.num_pb):
        name = 'sip_sdp/pb/{:05d}'.format(index)
        log.info("\t%s", name)
        tango_db.delete_device(name)


Instruction:
Can you write a function in Python 3 where it
blocks function to populate data in the heap.

Response:
def fill_buffer(heap_data, i_chan):
        """Blocking function to populate data in the heap.
        This is run in an executor.
        """
        # Calculate the time count and fraction.
        now = datetime.datetime.utcnow()
        time_full = now.timestamp()
        time_count = int(time_full)
        time_fraction = int((time_full - time_count) * (2**32 - 1))
        diff = now - (now.replace(hour=0, minute=0, second=0, microsecond=0))
        time_data = diff.seconds + 1e-6 * diff.microseconds

        # Write the data into the buffer.
        heap_data['visibility_timestamp_count'] = time_count
        heap_data['visibility_timestamp_fraction'] = time_fraction
        heap_data['correlator_output_data']['VIS'][:][:] = \
            time_data + i_chan * 1j


Instruction:
Make a summary of the following Python 3 code
async def _run_loop(self, executor):
        # SPEAD heap descriptor.
        # One channel per stream and one time index per heap.
        max_duration_sec = self._config['max_duration_sec']
        num_stations = self._config['heap']['num_stations']
        num_pols = self._config['heap']['num_pols']
        num_baselines = num_stations * (num_stations + 1) // 2
        reporting_interval_sec = self._config['reporting_interval_sec']
        start_chan = self._config['start_channel']
        dtype = [('TCI', 'i1'), ('FD', 'u1'), ('VIS', '<c8', num_pols)]
        descriptor = {
            'visibility_timestamp_count': {
                'id': 0x6000,
                'dtype': '<u4',
            },
            'visibility_timestamp_fraction': {
                'id': 0x6001,
                'dtype': '<u4',
            },
            'visibility_channel_id': {
                'id': 0x6002,
                'dtype': '<u4'
            },
            'visibility_channel_count': {
                'id': 0x6003,
                'dtype': '<u4'
            },
            'visibility_baseline_polarisation_id': {
                'id': 0x6004,
                'dtype': '<u4'
            },
            'visibility_baseline_count': {
                'id': 0x6005,
                'dtype': '<u4'
            },
            'phase_bin_id': {
                'id': 0x6006,
                'dtype': '<u2'
            },
            'phase_bin_count': {
                'id': 0x6007,
                'dtype': '<u2'
            },
            'scan_id': {
                'id': 0x6008,
                'dtype': '<u8'
            },
            'visibility_hardware_id': {
                'id': 0x6009,
                'dtype': '<u4'
            },
            'correlator_output_data': {
                'id': 0x600A,
                'dtype': dtype,
                'shape': (num_baselines,)
            }
        }

        # Create shadow heap buffers for each stream/channel.
        for i_buffer in range(2):
            self._buffer.append([])
            for _ in range(len(self._streams)):
                heap_data = {
                    'visibility_timestamp_count': 0,
                    'visibility_timestamp_fraction': 0,
                    'correlator_output_data': numpy.zeros(
                        (num_baselines,), dtype=dtype)
                }
                self._buffer[i_buffer].append(heap_data)

        # Add items to each stream's item group, and
        # send the start of stream message to each stream.
        tasks = []
        for i_stream, (stream, item_group) in enumerate(self._streams):
            for key, item in descriptor.items():
                item_shape = item['shape'] if 'shape' in item else tuple()
                item_group.add_item(
                    id=item['id'], name=key, description='',
                    shape=item_shape, dtype=item['dtype'])

            # Write the header information.
            item_group['visibility_channel_id'].value = i_stream + start_chan
            item_group['visibility_channel_count'].value = 1
            item_group['visibility_baseline_count'].value = num_baselines
            tasks.append(stream.async_send_heap(item_group.get_start()))
        await asyncio.gather(*tasks)

        # Calculate the total data size being sent.
        num_streams = self._config['num_streams']
        data_size = (num_baselines * (num_pols * 8 + 2)) / 1e6
        self._log.info('Heap size is %.3f MB', data_size)

        # Enter the main loop over time samples.
        done = False
        loop = asyncio.get_event_loop()
        heaps_sent = 0
        i_time = 0
        start_time = time.time()
        timer1 = time.time()
        while not done:
            # Schedule sends for the previous buffer, if available.
            tasks = []
            if i_time > 0:
                i_buffer = (i_time - 1) % 2
                for i_stream, (stream, item_group) in enumerate(self._streams):
                    for key, value in self._buffer[i_buffer][i_stream].items():
                        item_group[key].value = value  # Update values in heap.
                    # Always send the descriptors AND the static data!
                    tasks.append(stream.async_send_heap(
                        item_group.get_heap(descriptors='all', data='all')))
                    heaps_sent += 1

            # Fill a buffer by distributing it among worker threads.
            i_buffer = i_time % 2
            for i_stream in range(num_streams):
                tasks.append(loop.run_in_executor(
                    executor, self.fill_buffer,
                    self._buffer[i_buffer][i_stream], i_stream))

            # Ensure processing tasks and previous asynchronous sends are done.
            await asyncio.gather(*tasks)

            # Increment time index.
            i_time += 1

            # Periodically report the sender data rate.
            now = time.time()
            if (now - timer1) >= reporting_interval_sec:
                self._log.info('Sent %i heaps in %.3f sec (%.1f MB/s)',
                               heaps_sent, (now - timer1),
                               (data_size * heaps_sent) / (now - timer1))
                heaps_sent = 0
                timer1 = now

            # Check for completion.
            if now - start_time > max_duration_sec > 0:
                done = True

        # End the streams.
        tasks = []
        for stream, item_group in self._streams:
            tasks.append(stream.async_send_heap(item_group.get_end()))
        await asyncio.gather(*tasks)

Response: Main loop for the SPEAD heap.


Instruction:
Implement a function in Python 3 to
mark the specified object as completed.

Response:
def set_complete(self, object_id: str):
        """Mark the specified object as completed."""
        if object_id in self.active:
            DB.remove_from_list('{}:active'.format(self.type), object_id)
            DB.append_to_list('{}:completed'.format(self.type), object_id)


Instruction:
How would you explain what the following Python 3 function does
def publish(self, object_id: str, event_type: str,
                event_data: dict = None):
        """Publish a scheduling object event.

        Args:
            object_id (str): ID of the scheduling object
            event_type (str): Type of event.
            event_data (dict, optional): Event data.

        """
        object_key = SchedulingObject.get_key(self.type, object_id)
        publish(event_type=event_type,
                event_data=event_data,
                object_type=self.type,
                object_id=object_id,
                object_key=object_key,
                origin=None)

Response: Publish a scheduling object event.


Instruction:
Write a Python 3 script for
starting a workflow stage by starting a number of docker services.

Response:
def _start_workflow_stages(pb: ProcessingBlock, pb_id: str,
                           workflow_stage_dict: dict,
                           workflow_stage: WorkflowStage,
                           docker: DockerSwarmClient):
    """Start a workflow stage by starting a number of docker services.

    This function first assesses if the specified workflow stage can be
    started based on its dependencies. If this is found to be the case,
    the workflow stage is stared by first resolving and template arguments
    in the workflow stage configuration, and then using the Docker Swarm Client
    API to start workflow stage services. As part of this, the
    workflow_stage_dict data structure is updated accordingly.

    TODO(BMo) This function will need refactoring at some point as part
    of an update to the way workflow state metadata is stored in the
    configuration database. Currently the stage_data dictionary
    is a bit of a hack for a badly specified Configuration Database
    backed WorkflowStage object.

    This function is used by `execute_processing_block`.

    Args:
        pb (ProcessingBlock): Configuration database Processing Block data
            object
        pb_id (str): Processing Block identifier
        workflow_stage_dict (dict): Workflow stage metadata structure
        workflow_stage (WorkflowStage): Workflow state configuration database
            data object.
        docker (DockerClient): Docker Swarm Client object.

    """
    # FIXME(BMo) replace pb_id argument, get this from the pb instead!
    stage_data = workflow_stage_dict[workflow_stage.id]
    stage_data['start'] = False

    # Determine if the stage can be started.
    if stage_data['status'] == 'none':
        if not workflow_stage.dependencies:
            stage_data['start'] = True
        else:
            dependency_status = []
            for dependency in workflow_stage.dependencies:
                dependency_status.append(
                    workflow_stage_dict[dependency['value']][
                        'status'] == 'complete')
                # ii += 1
            stage_data['start'] = all(dependency_status)

    # Start the workflow stage.
    if stage_data['start']:
        # Configure EE (set up templates)
        LOG.info('-- Starting workflow stage: %s --', workflow_stage.id)
        LOG.info('Configuring EE templates.')
        args_template = jinja2.Template(workflow_stage.args_template)
        stage_params = pb.workflow_parameters[workflow_stage.id]
        template_params = {**workflow_stage.config, **stage_params}
        args = args_template.render(stage=template_params)
        LOG.info('Resolving workflow script arguments.')

        args = json.dumps(json.loads(args))
        compose_template = jinja2.Template(
            workflow_stage.compose_template)
        compose_str = compose_template.render(stage=dict(args=args))

        # Prefix service names with the PB id
        compose_dict = yaml.load(compose_str)
        service_names = compose_dict['services'].keys()
        new_service_names = [
            '{}_{}_{}'.format(pb_id, pb.workflow_id, name)
            for name in service_names]
        for new, old in zip(new_service_names, service_names):
            compose_dict['services'][new] = \
                compose_dict['services'].pop(old)
        compose_str = yaml.dump(compose_dict)

        # Run the compose file
        service_ids = docker.create_services(compose_str)
        LOG.info('Staring workflow containers:')
        for service_id in service_ids:
            service_name = docker.get_service_name(service_id)
            LOG.info("  %s, %s ", service_name, service_id)
            stage_data['services'][service_id] = {}
            LOG.info('Created Services: %s', service_ids)
            stage_data['services'][service_id] = dict(
                name=docker.get_service_name(service_id),
                status='running',
                complete=False
            )
        stage_data["status"] = 'running'


Instruction:
Implement a function in Python 3 to
check and update the status of a workflow stage. This function checks and updates the status of a workflow stage specified by the parameters in the specified stage_data dictionary. If the workflow stage is not marked as complete, this function will check with the Docker Swarm API on the status of Docker services defined for the stage. If **all** services are found to be complete (based on their service state being reported as 'shutdown', the workflow stage is marked complete. This function is used by `execute_processing_block`. TODO(BMo) This function will need refactoring at some point as part of an update to the way workflow state metadata is stored in the configuration database. Currently the stage_data dictionary is a bit of a hack for a badly specified Configuration Database backed WorkflowStage object. Args: stage_data (dict): Dictionary holding workflow stage metadata. workflow_stage (WorkflowStage): Workflow stage data object. docker (DockerClient): Docker Swarm Client object.

Response:
def _update_workflow_stages(stage_data: dict, workflow_stage: WorkflowStage,
                            docker: DockerSwarmClient):
    """Check and update the status of a workflow stage.

    This function checks and updates the status of a workflow stage
    specified by the parameters in the specified stage_data dictionary.

    If the workflow stage is not marked as complete, this function will
    check with the Docker Swarm API on the status of Docker services
    defined for the stage. If **all** services are found to be complete
    (based on their service state being reported as 'shutdown',
    the workflow stage is marked complete.

    This function is used by `execute_processing_block`.

    TODO(BMo) This function will need refactoring at some point as part
        of an update to the way workflow state metadata is stored in the
        configuration database. Currently the stage_data dictionary
        is a bit of a hack for a badly specified Configuration Database
        backed WorkflowStage object.

    Args:
        stage_data (dict): Dictionary holding workflow stage metadata.
        workflow_stage (WorkflowStage): Workflow stage data object.
        docker (DockerClient): Docker Swarm Client object.

    """
    service_status_complete = []

    # FIXME(BMo) is not "complete" -> is "running"
    if stage_data["status"] != "complete":
        for service_id, service_dict in stage_data['services'].items():
            service_state = docker.get_service_state(service_id)
            if service_state == 'shutdown':
                docker.delete_service(service_id)
            service_dict['status'] = service_state
            service_dict['complete'] = (service_state == 'shutdown')
            service_status_complete.append(service_dict['complete'])
            if all(service_status_complete):
                LOG.info('Workflow stage service %s complete!',
                         workflow_stage.id)
                stage_data['status'] = "complete"


Instruction:
Explain what the following Python 3 code does
def _abort_workflow(pb: ProcessingBlock, workflow_stage_dict: dict,
                    docker: DockerSwarmClient):
    """Abort the workflow.

    TODO(BMo): This function currently does nothing as the abort flag
        is hardcoded to False!

    This function is used by `execute_processing_block`.

    Args:
        pb (ProcessingBlock): Configuration database Processing block object.
        workflow_stage_dict (dict): Workflow stage metadata dictionary.
        docker (DockerClient): Docker Swarm Client object.

    Returns:
        bool, True if the stage is aborted, otherwise False.

    """
    # TODO(BMo) Ask the database if the abort flag on the PB is set.
    _abort_flag = False
    if _abort_flag:
        for workflow_stage in pb.workflow_stages:
            for service_id, _ in \
                    workflow_stage_dict[workflow_stage.id]['services'].items():
                docker.delete_service(service_id)
                LOG.info("Deleted Service Id %s", service_id)
        return True
    return False

Response:
Abort the workflow.

    TODO(BMo): This function currently does nothing as the abort flag
        is hardcoded to False!

    This function is used by `execute_processing_block`.

    Args:
        pb (ProcessingBlock): Configuration database Processing block object.
        workflow_stage_dict (dict): Workflow stage metadata dictionary.
        docker (DockerClient): Docker Swarm Client object.

    Returns:
        bool, True if the stage is aborted, otherwise False.


Instruction:
Here you have a function in Python 3, explain what it does
def _workflow_complete(workflow_stage_dict: dict):
    # Check if all stages are complete, if so end the PBC by breaking
    # out of the while loop
    complete_stages = []
    for _, stage_config in workflow_stage_dict.items():
        complete_stages.append((stage_config['status'] == 'complete'))
    if all(complete_stages):
        LOG.info('PB workflow complete!')
        return True
    return False

Response: Check if the entire workflow is complete.


Instruction:
Write a Python 3 function that can
execute a processing block.

Response:
def execute_processing_block(pb_id: str, log_level='DEBUG'):
    """Execute a processing block.

    Celery tasks that executes a workflow defined in a Configuration database
    Processing Block data object.

    Args:
        pb_id (str): The PB id for the PBC
        log_level (str): Python logging level.

    """
    init_logger('sip', show_log_origin=True, propagate=False,
                log_level=log_level)
    LOG.info('+' * 40)
    LOG.info('+ Executing Processing block: %s!', pb_id)
    LOG.info('+' * 40)
    LOG.info('Processing Block Controller version: %s', __version__)
    LOG.info('Docker Swarm API version: %s', sip_swarm_api_version)
    LOG.info('Configuration database API version: %s', config_db_version)

    pb = ProcessingBlock(pb_id)

    LOG.info('Starting workflow %s %s', pb.workflow_id, pb.workflow_version)

    pb.set_status('running')
    docker = DockerSwarmClient()

    # Coping workflow stages to a dict
    workflow_stage_dict = {}
    for stage in pb.workflow_stages:
        workflow_stage_dict[stage.id] = deepcopy(stage.config)
        workflow_stage_dict[stage.id]['services'] = dict()

    # Loop until workflow stages are complete.
    while True:
        time.sleep(0.1)

        for workflow_stage in pb.workflow_stages:

            _start_workflow_stages(pb, pb_id, workflow_stage_dict,
                                   workflow_stage, docker)

            _update_workflow_stages(workflow_stage_dict[workflow_stage.id],
                                    workflow_stage, docker)

        if _abort_workflow(pb, workflow_stage_dict, docker):
            break

        if _workflow_complete(workflow_stage_dict):
            break

    pb_list = ProcessingBlockList()
    pb_list.set_complete(pb_id)
    pb.set_status('completed')
    LOG.info('-' * 40)
    LOG.info('- Destroying PBC for %s', pb_id)
    LOG.info('-' * 40)
    return pb.status


Instruction:
Explain what the following Python 3 code does
def put(self, block_id, priority, pb_type='offline'):
        if pb_type not in ('offline', 'realtime'):
            raise ValueError('Invalid PB type.')

        with self._mutex:
            added_time = datetime.datetime.utcnow().isoformat()
            entry = (priority, sys.maxsize-self._index, block_id, pb_type,
                     added_time)
            self._index += 1
            if self._block_map.get(block_id) is not None:
                raise KeyError('ERROR: Block id "{}" already exists in '
                               'PC PB queue!'.
                               format(block_id))
            self._block_map[block_id] = entry
            LOG.debug("Adding PB %s to queue", block_id)
            self._queue.append(entry)
            self._queue.sort()  # Sort by priority followed by insertion order.
            self._queue.reverse()

Response: Adds a new entry to the processing block queue.


Instruction:
Write a Python 3 function for
getting the highest priority Processing Block from the queue.

Response:
def get(self):
        """Get the highest priority Processing Block from the queue."""
        with self._mutex:
            entry = self._queue.pop()
            del self._block_map[entry[2]]
            return entry[2]


Instruction:
Implement a Python 3 function for
removing a Processing Block from the queue.

Response:
def remove(self, block_id):
        """Remove a Processing Block from the queue.

        Args:
            block_id (str):
        """
        with self._mutex:
            entry = self._block_map[block_id]
            self._queue.remove(entry)


Instruction:
Can you implement a function in Python 3 that
returns a list of ServiceState objects known to SDP.

Response:
def get_service_state_list() -> List[ServiceState]:
    """Return a list of ServiceState objects known to SDP."""
    keys = DB.get_keys('states*')
    LOG.debug('Loading list of known services.')
    services = []
    for key in keys:
        values = key.split(':')
        if len(values) == 4:
            services.append(ServiceState(*values[1:4]))
    return services


Instruction:
How would you implement a function in Python 3 that
returns list of Services.

Response:
def get_service_id_list() -> List[tuple]:
    """Return list of Services."""
    keys = DB.get_keys('states*')
    services = []
    for key in keys:
        values = key.split(':')
        if len(values) == 4:
            services.append(':'.join(values[1:]))
    return services


Instruction:
Write a Python 3 script for
returning the list of Processing Blocks known to SDP.

Response:
def get():
    """Return the list of Processing Blocks known to SDP."""

    LOG.debug('GET Processing Block list')
    _url = get_root_url()

    # Get list of Processing block Ids
    block_ids = sorted(DB.get_processing_block_ids())
    LOG.debug('Processing Block IDs: %s', block_ids)

    # Construct response object
    response = dict(num_processing_blocks=len(block_ids),
                    processing_blocks=list())

    # Loop over blocks and add block summary to response.
    for block in DB.get_block_details(block_ids):
        block_id = block['id']
        LOG.debug('Creating PB summary for %s', block_id)
        block['links'] = dict(
            detail='{}/processing-block/{}'.format(_url, block_id),
            scheduling_block='{}/scheduling-block/{}'
            .format(_url, block_id.split(':')[0])
        )
        response['processing_blocks'].append(block)
    response['links'] = {
        'self': '{}'.format(request.url),
        'home': '{}'.format(_url)
    }
    return response, HTTPStatus.OK


Instruction:
Here you have a function in Python 3, explain what it does
def config(self) -> dict:
        # Check that the key exists
        self._check_object_exists()
        config_dict = DB.get_hash_dict(self.key)
        for _, value in config_dict.items():
            for char in ['[', '{']:
                if char in value:
                    value = ast.literal_eval(value)
        return config_dict

Response: Get the scheduling object config.


Instruction:
How would you explain what the following Python 3 function does
def get_property(self, property_key: str) -> str:
        self._check_object_exists()
        return DB.get_hash_value(self.key, property_key)

Response: Get a scheduling object property.


Instruction:
Write a Python 3 function for
setting the status of the scheduling object.

Response:
def set_status(self, value):
        """Set the status of the scheduling object."""
        self._check_object_exists()
        DB.set_hash_value(self.key, 'status', value)
        self.publish('status_changed', event_data=dict(status=value))


Instruction:
How would you explain what the following Python 3 function does
def publish(self, event_type: str, event_data: dict = None):
        import inspect
        import os.path
        _stack = inspect.stack()
        _origin = os.path.basename(_stack[3][1]) + '::' + \
            _stack[3][3]+'::L{}'.format(_stack[3][2])

        publish(event_type=event_type,
                event_data=event_data,
                object_type=self._type,
                object_id=self._id,
                object_key=self._key,
                origin=_origin)

Response: Publish an event associated with the object.


Instruction:
Explain what the following Python 3 code does
def get_events(self) -> List[Event]:
        LOG.debug('Getting events for %s', self.key)
        return get_events(self.key)

Response: Get the list of events associated with the scheduling object.


Instruction:
Can you tell what is the following Python 3 function doing
def _check_object_exists(self):
        if not DB.get_keys(self.key):
            raise KeyError("Object with key '{}' not exist".format(self.key))

Response: Raise a KeyError if the object does not exist in the database.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_service_state_object_id(subsystem: str, name: str,
                                    version: str) -> str:
        """Return service state data object key.

        Args:
            subsystem (str): Subsystem the service belongs to
            name (str): Name of the Service
            version (str): Version of the Service

        Returns:
            str, Key used to store the service state data object

        """
        return '{}:{}:{}'.format(subsystem, name, version)

Response: Return the service state data object key.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def create_services(self, compose_str: str) -> list:
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Services can only be run on '
                               'swarm manager nodes')

        # Initialise empty list
        services_ids = []

        try:
            service_config = yaml.load(compose_str)

            # Deepcopy the service config
            service_list = copy.deepcopy(service_config)

            # Removing version and service from the dict
            service_config.pop('version')
            service_config.pop('services')

            for service_name in service_list['services']:
                service_exist = self._client.services.list(
                    filters={'name': service_name})
                if not service_exist:
                    service_config['name'] = service_name
                    service_spec = self._parse_services(
                        service_config, service_name, service_list)
                    created_service = self._client.services.create(
                        **service_spec)
                    service_id = created_service.short_id
                    LOG.debug('Service created: %s', service_id)
                    services_ids.append(service_id)
                else:
                    LOG.debug('Services already exists')

        except yaml.YAMLError as exc:
            print(exc)

        # Returning list of services created
        return services_ids

Response:
Create new docker services.

        Args:
            compose_str (string): Docker compose 'file' string

        Return:
            service_names, list


Instruction:
Can you write a function in Python 3 where it
creates a new docker volume.

Response:
def create_volume(self, volume_name: str, driver_spec: str = None):
        """Create new docker volumes.

        Only the manager nodes can create a volume

        Args:
            volume_name (string): Name for the new docker volume
            driver_spec (string): Driver for the docker volume
        """
        # Default values
        if driver_spec:
            driver = driver_spec
        else:
            driver = 'local'

        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Services can only be deleted '
                               'on swarm manager nodes')

        self._client.volumes.create(name=volume_name, driver=driver)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def delete_service(self, service: str):
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Services can only be deleted '
                               'on swarm manager nodes')

        # Remove service
        self._api_client.remove_service(service)

Response: Removes a docker service.


Instruction:
Can you write a function in Python 3 where it
removes all services in the cluster.

Response:
def delete_all_services(self):
        """Removes/stops a service.

        Only the manager nodes can delete a service
        """
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Services can only be deleted '
                               'on swarm manager nodes')

        service_list = self.get_service_list()
        for services in service_list:
            # Remove all the services
            self._api_client.remove_service(services)


Instruction:
Given the following Python 3 function, write the documentation
def delete_volume(self, volume_name: str):
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Volumes can only be deleted '
                               'on swarm manager nodes')

        # Remove volume
        self._api_client.remove_volume(volume_name)

Response: Removes a docker volume.


Instruction:
Write a Python 3 script to
remove all the volumes.

Response:
def delete_all_volumes(self):
        """Remove all the volumes.

        Only the manager nodes can delete a volume
        """
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Volumes can only be deleted '
                               'on swarm manager nodes')

        volume_list = self.get_volume_list()
        for volumes in volume_list:
            # Remove all the services
            self._api_client.remove_volume(volumes, force=True)


Instruction:
Can you tell what is the following Python 3 function doing
def get_service_list(self) -> list:
        # Initialising empty list
        services = []

        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can retrieve'
                               ' all the services.')

        service_list = self._client.services.list()
        for s_list in service_list:
            services.append(s_list.short_id)
        return services

Response: Get a list of docker services.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_service_name(self, service_id: str) -> str:
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can retrieve all'
                               ' the services details.')

        service = self._client.services.get(service_id)
        return service.name

Response: Get the name of the docker service.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_service_details(self, service_id: str) -> dict:
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can retrieve all'
                               ' the services details.')

        service = self._client.services.get(service_id)
        return service.attrs

Response: Get details of a service.


Instruction:
Write a Python 3 function that can
get the state of the service.

Response:
def get_service_state(self, service_id: str) -> str:
        """Get the state of the service.

        Only the manager nodes can retrieve service state

        Args:
            service_id (str): Service id

        Returns:
            str, state of the service

        """
        # Get service
        service = self._client.services.get(service_id)

        # Get the state of the service
        for service_task in service.tasks():
            service_state = service_task['DesiredState']
        return service_state


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_node_list(self) -> list:
        # Initialising empty list
        nodes = []

        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node '
                               'can retrieve all the nodes.')

        node_list = self._client.nodes.list()
        for n_list in node_list:
            nodes.append(n_list.id)
        return nodes

Response: Get a list of nodes.


Instruction:
Can you write a function in Python 3 where it
gets details of a node.

Response:
def get_node_details(self, node_id: list) -> dict:
        """Get details of a node.

        Only the manager nodes can retrieve details of a node

        Args:
            node_id (list): List of node ID

        Returns:
            dict, details of the node

        """
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can '
                               'retrieve node details.')

        node = self._client.nodes.get(node_id)
        return node.attrs


Instruction:
Can you tell what is the following Python 3 function doing
def get_container_list(self) -> list:
        # Initialising empty list
        containers = []

        containers_list = self._client.containers.list()
        for c_list in containers_list:
            containers.append(c_list.short_id)
        return containers

Response: Get list of containers.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_container_details(self, container_id_or_name: str) -> dict:
        container = self._client.containers.get(container_id_or_name)
        return container.attrs

Response: Get details of a container.


Instruction:
Implement a function in Python 3 to
get a list of docker volumes.

Response:
def get_volume_list(self) -> list:
        """Get a list of docker volumes.

        Only the manager nodes can retrieve all the volumes

        Returns:
            list, all the names of the volumes in swarm

        """
        # Initialising empty list
        volumes = []

        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can retrieve'
                               ' all the services.')

        volume_list = self._client.volumes.list()
        for v_list in volume_list:
            volumes.append(v_list.name)
        return volumes


Instruction:
Create a Python 3 function to
get details of the volume.

Response:
def get_volume_details(self, volume_name: str) -> dict:
        """Get details of the volume.

        Args:
            volume_name (str): Name of the volume

        Returns:
            dict, details of the volume

        """
        if volume_name not in self.volumes:
            raise RuntimeError('No such volume found: ', volume_name)

        volume = self._client.volumes.get(volume_name)
        return volume.attrs


Instruction:
Given the following Python 3 function, write the documentation
def get_actual_replica(self, service_id: str) -> str:
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can retrieve '
                               'replication level of the service')

        service_details = self.get_service_details(service_id)
        actual_replica = service_details["Spec"]["Mode"][
            "Replicated"]["Replicas"]
        return actual_replica

Response: Get the actual replica level of a service.


Instruction:
Here you have a function in Python 3, explain what it does
def get_replicas(self, service_id: str) -> str:
        # Initialising empty list
        replicas = []

        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can retrieve '
                               'replication level of the service')

        service_tasks = self._client.services.get(service_id).tasks()
        for task in service_tasks:
            if task['Status']['State'] == "running":
                replicas.append(task)
        return len(replicas)

Response: Get the replication level of a service.


Instruction:
Explain what the following Python 3 code does
def update_labels(self, node_name: str, labels: dict):
        # Raise an exception if we are not a manager
        if not self._manager:
            raise RuntimeError('Only the Swarm manager node can update '
                               'node details.')

        # Node specification
        node_spec = {'Availability': 'active',
                     'Name': node_name,
                     'Role': 'manager',
                     'Labels': labels}
        node = self._client.nodes.get(node_name)
        node.update(node_spec)

Response: Update the labels of a node.