Beispiel #1
0
    def createComment(self, comments):
        '''
        Create a list of comments associated with the shipment.

        Args:
            comments (list[str]): a list of comments to be created.
        '''

        # Perform type checking on the provided args
        if not self.expert and not isinstance(comments, list) and [
                comment
                for comment in comments if not isinstance(comment, str)
        ] != []:
            WARNING('Comment(s) must be given as a list of strings.')
            INFO('No comment(s) created.')
            return False

        # Create the comments and fetch the updated json
        dbCommands['createShipmentComment'].run(shipment=self.shipment,
                                                comments=comments)
        if not self.expert:
            self.get()
            comments_new = self.json['comments'][(len(self.json['comments']) -
                                                  len(comments)):]
            INFO('Comment code(s) {0} created for shipment id {1}.'.format(
                ', '.join([comment['code'] for comment in comments_new]),
                self.shipment))
        return True
Beispiel #2
0
    def deleteComment(self, code):
        '''
        Delete a comment associated with the component.

        Args:
            code (str): the code for the comment to be deleted.
        '''

        # Check that the comment code is associated with a comment for the component
        if not self.expert and code not in [
                comment['code'] for comment in self.json['comments']
        ]:
            WARNING(
                'Code {0} is not associated with any comments of component code {1}.'
                .format(code, self.component))
            INFO('No comments deleted.')
            return False

        # Delete the comment and fetch the updated json
        dbCommands['deleteComponentComment'].run(component=self.component,
                                                 code=code)
        if not self.expert:
            self.get()
            INFO('Comment code {0} deleted from component code {1}.'.format(
                code, self.component))
        return True
Beispiel #3
0
    def setStage(self, stage):
        '''
        Set the stage for the component.

        Args:
            stage (str): the code for the stage of the component.
        '''

        if not self.expert:

            # If we haven't retrieved the json for the component type, do so now
            if self.componentType_json == None:
                self.__getComponentType()

            # Check if stage is in the component type's associated stages
            if stage not in [
                    stage['code']
                    for stage in self.componentType_json['stages']
            ]:
                WARNING(
                    'Stage \'{0}\' is not associated with component type \'{1}\'.'
                    .format(stage, self.type['code']))
                INFO('Stage not set.')
                return False

        # Update the stage and fetch the updated json
        dbCommands['setComponentStage'].run(component=self.component,
                                            stage=self.stage)
        if not self.expert:
            self.get()
            INFO('Component code {0} updated to stage \'{1}\'.'.format(
                self.component, stage))
        return True
Beispiel #4
0
    def updateComment(self, code, comment):
        '''
        Update a comment associated with the shipment.

        Args:
            code (str): the code for the comment to be updated.
            comment (str): the content the comment will be updated with.
        '''

        # Check the provided code to see if it's associated with a comment of the shipment
        if not self.expert and code not in [
                comment['code'] for comment in self.json['comments']
        ]:
            WARNING(
                'Code {0} is not associated with any comments of shipment id {1}.'
                .format(code, self.shipment))
            INFO('No comments deleted.')
            return False

        # Update the comment and fetch the updated json
        dbCommands['updateShipmentComment'].run(shipment=self.shipment,
                                                code=code,
                                                comment=comment)
        if not self.expert:
            self.get()
            INFO('Comment code {0} updated for shipment id {1}.'.format(
                code, self.shipment))
        return True
Beispiel #5
0
 def __startUp(self):
     if self._institutions == [] or self._projects == []:
         print('')
         INFO('Running ITk Production Database content summary interface.')
         INFO('Updating list of institutions and projects.')
         self._institutions = dbCommands['listInstitutions'].run()
         self._projects = dbCommands['listProjects'].run()
Beispiel #6
0
    def updateAttachment(self, code, title=None, description=None):
        '''
        Update an attachment associated with the shipment.

        Args:
            title (str): the updated title for the attachment (default: None).
            description (str): the updated description for the attachment (default: None).
        '''

        # Check the provided code to see if it's associated with an attachment of the shipment
        if not self.expert and code not in [
                attachment['code'] for attachment in self.json['attachments']
        ]:
            WARNING(
                'Code {0} is not associated with any attachments of shipment id {1}.'
                .format(code, self.shipment))
            INFO('No attachments updated.')
            return False

        # Fetch our args and remove any keys with values set to None
        kwargs = {
            'shipment': self.shipment,
            'code': code,
            'title': title,
            'description': description
        }
        dtoIn = {k: v for k, v in kwargs.items() if v is not None}

        # Update the attachment and fetch the updated json
        dbCommands['updateShipmentAttachment'].run(**dtoIn)
        if not self.expert:
            self.get()
            INFO('Attachment code {0} updated for shipment id {1}.'.format(
                code, self.shipment))
        return True
Beispiel #7
0
    def deleteAttachment(self, code):
        '''
        Delete an attachment associated with the shipment.

        Args:
            code (str): the code for attachment to be deleted.
        '''

        # Check the provided code to see if it's associated with an attachment of the shipment
        if not self.expert and code not in [
                attachment['code'] for attachment in self.json['attachments']
        ]:
            WARNING(
                'Code {0} is not associated with any attachments of shipment id {1}.'
                .format(code, self.shipment))
            INFO('No attachments deleted.')
            return False

        # Delete the attachment and fetch the updated json
        dbCommands['deleteShipmentAttachment'].run(shipment=self.shipment,
                                                   code=code)
        if not self.expert:
            self.get()
            INFO('Attachment code {0} deleted from shipment id {1}.'.format(
                code, self.shipment))
        return True
Beispiel #8
0
    def createComment(self, comments):
        '''
        Create a list of comments associated with the component.

        Args:
            comments (list[str]): a list of comments to be created.
        '''

        if not self.expert:

            if not isinstance(comments, list) and [
                    comment
                    for comment in comments if not isinstance(comment, str)
            ] != []:
                WARNING('Comment(s) must be given as a list of strings.')
                INFO('No comment(s) created.')
                return False

        # Add the comments and fetch the updated json
        dbCommands['createComponentComment'].run(component=self.component,
                                                 comments=comments)
        if not self.expert:
            self.get()

            # Report the codes for the new comments (at the end of the comments list from the json)
            comments_new = self.json['comments'][(len(self.json['comments']) -
                                                  len(comments)):]
            INFO('Comment code(s) {0} created for component code {1}.'.format(
                ', '.join([comment['code'] for comment in comments_new]),
                self.component))
        return True
Beispiel #9
0
 def listComponentTypes(self):
     INFO('Fetching a list of component types associated with project code \'{0}\' from the ITkPD...'.format(self.project))
     timestamp = time.strftime('%Y/%m/%d-%H:%M:%S')
     componentTypes = [{'name': componentType['name'], 'code': componentType['code']} for componentType in dbCommands['listComponentTypes'].run(project = self.project)]
     INFO('Printing list of component types:\n'.format(self.project))
     self.__printNamesAndCodes(componentTypes)
     print('')
     if self.savePath != None:
         self.__save({'timestamp': timestamp, 'function': 'listComponentTypes', 'args': {'project': self.project}, 'content': componentTypes})
Beispiel #10
0
    def __askForMultipleThings(self, prompt, options):

        # Generate our list of codes
        codes = [item['code'] for item in options]
        PROMPT(prompt)

        # If _always_print, print the available options
        if self._always_print:
            INFO('Printing options:\n')
            self.__printNamesAndCodes(options)
            print('')
            PROMPT('Please enter a space separated list of codes from above:')

        while True:

            # Get our user input
            response = input().strip().upper().split()

            # If nothing, do nothing
            if response == []:
                continue

            # Escape code &PRINT -- print the available options
            elif response == ['&PRINT']:
                INFO('Printing options:\n')
                self.__printNamesAndCodes(options)
                print('')
                PROMPT(
                    'Please enter a list of space separated codes from above:')
                continue

            # Escape code &ALL -- select all available options
            elif response == ['&ALL']:
                INFO('Using all options.')
                return codes

            # Escape code &CANCEL -- raise Cancel exception
            elif response == ['&CANCEL']:
                WARNING('Session cancelled.')
                raise Cancel

            # If the user enters a valid list of codes, return that code and its index
            not_allowed = [code for code in response if code not in codes]
            if not_allowed == []:
                return_list = []
                INFO('Using code(s):\n')
                for code in response:
                    i = codes.index(code)
                    return_list.append(code)
                    print('    {0} ({1})'.format(code, options[i]['name']))
                print('')
                return return_list

            # Else the input is invalid
            else:
                PROMPT('Invalid input, please try again:')
                continue
Beispiel #11
0
 def listInstitutions(self):
     INFO('Fetching a list of institutions from the ITkPD...')
     timestamp = time.strftime('%Y/%m/%d-%H:%M:%S')
     institutions = [{'name': institution['name'], 'code': institution['code']} for institution in dbCommands['listInstitutions'].run()]
     INFO('Printing list of institutions:\n')
     self.__printNamesAndCodes(institutions)
     print('')
     if self.savePath != None:
         self.__save({'timestamp': timestamp, 'function': 'listInstitutions', 'args': {}, 'content': institutions})
Beispiel #12
0
 def __startUp(self):
     if self.institutions == []:
         print('')
         INFO(
             'Running ITk Production Database component registration interface.'
         )
         self.ITkPDSession.authenticate()
         INFO('Updating list of institutions.')
         self.institutions = self.ITkPDSession.doSomething(
             action='listInstitutions', method='GET', data={})
Beispiel #13
0
    def setProperty(self, code, value):
        '''
        Set a property for the component.

        Args:
            code (str): the code for the property to be set.
            value (int|float|str|bool): the value for the property.
        '''

        if not self.expert:

            # If we haven't retrieved the json for the component type, do so now
            if self.componentType_json == None:
                self.__getComponentType()

            # Check if the property code is in the component type's associated properties
            properties = [
                property['code']
                for property in self.componentType_json['properties']
            ]
            if code not in properties:
                WARNING(
                    'Property \'{0}\' is not associated with component type \'{1}\'.'
                    .format(property, self.type['code']))
                INFO('Property not set.')
                return False

            i = properties.index(code)

            # Check if the value is set to None and if the property is required (i.e., cannot be set to None)
            if value == None and properties[i]['required']:
                WARNING(
                    'Property \'{0}\' is required and cannot be set to None.'.
                    format(property))
                INFO('Property not set.')
                return False

            # Check that the value of the property has the right type (if not None)
            elif not self.__isType(value, properties[i]['dataType']):
                WARNING(
                    'Property \'{0}\' is not associated with component type \'{1}\'.'
                    .format(property, self.type['code']))
                INFO('Property not set.')
                return False

        # Update the stage and fetch the updated json
        dbCommands['setComponentProperty'].run(component=self.component,
                                               code=code,
                                               value=value)
        if not self.expert:
            self.get()
            INFO('Component code {0} updated to stage \'{1}\'.'.format(
                self.component, stage))
        return True
Beispiel #14
0
    def __askForSomething(self, prompt, options):

        # Generate our list of codes
        codes = [item['code'] for item in options]
        PROMPT(prompt)

        # If always_print, print the available options for the code
        if self.always_print:
            INFO('Printing options:\n')
            self.__printNamesAndCodes(options)
            print('')
            PROMPT('Please enter a code from above:')

        while True:

            # Get our user input
            response = input().upper().strip()

            # If nothing, do nothing
            if response == '':
                continue

            # Escape code &PRINT -- print the available options
            elif response == '&PRINT':
                INFO('Printing options:\n')
                self.__printNamesAndCodes(options)
                print('')
                PROMPT('Please enter a code from above:')

            # Escape code &JSON -- print JSON to show what has already been selected
            elif response == '&JSON':
                INFO('Printing JSON:\n')
                pp.pprint(self.json)
                print('')
                PROMPT('Please enter a code:')

            # Escape code &CANCEL -- raise our Cancel exception
            elif response == '&CANCEL':
                WARNING('Registration cancelled.')
                raise Cancel

            # If the user enters a valid code, return that code and its index
            elif response in codes:
                i = codes.index(response)
                INFO('Using code: {0} ({1})'.format(response,
                                                    options[i]['name']))
                return i, response

            # Else the input is invalid
            else:
                PROMPT('Invalid input, please try again:')
                continue
Beispiel #15
0
    def createAttachment(self, data, title=None, description=None):
        '''
        Create an attachment with binary data and add it to the shipment.

        Args:
            data (bin str): binary data to be uploaded.
            title (str): the title for the attachment (default: None).
            description (str): the description for the attachment (default: None)
        '''

        # Fetch our args and remove any keys with values set to None
        kwargs = {
            'shipment': self.shipment,
            'title': title,
            'description': description,
            'data': data
        }
        dtoIn = {k: v for k, v in kwargs.items() if v is not None}

        # Create the attachment and fetch the updated json
        dbCommands['createShipmentAttachment'].run(**dtoIn)
        if not self.expert:
            self.get()
            INFO('Attachment code {0} created for shipment id {1}.'.format(
                self.json['attachments'][-1]['code'], self.shipment))
        return True
def getIndices(table_length):
    PROMPT(
        'Enter a list of positive, space-separated, integer indices from the table above, \'all\' to select all items, or \'none\' to select no items:'
    )
    while True:
        response = input().strip()
        try:
            if response == '':
                continue
            elif response == 'none':
                INFO('No items were seleted.')
                return []
            elif response == 'all':
                return list(range(table_length))
            else:
                response_split = [
                    item for sublist in response.strip().split()
                    for item in sublist.split(',')
                ]
                indices = [[int(index)] if '-' not in index else list(
                    range(int(index.split('-')[0]),
                          int(index.split('-')[1]) + 1))
                           for index in response_split]
                indices = [
                    index for sublist in indices for index in sublist
                    if index < table_length
                ]
                return sorted(list(set(indices)))
        except ValueError:
            del response
            PROMPT(
                'Invalid input. Please enter a list of positive, space-separated integers, \'all\', or \'none\':'
            )
            continue
Beispiel #17
0
    def __cutOnValue(self, component, allowedValues, keywords):

        try:

            # Get value at the level of the first keyword
            value = component[keywords[0]]

            # If there are multiple keywords, continue to update value (note, the order of the keywords should match the order in the uuComponent object)
            for keyword in keywords[1:]:
                value = value[keyword]

            # If the value passes the cut, return True
            if value in allowedValues:
                return True

            # If the value fails the cut, return False
            else:
                if self.verbose:
                    INFO('Component \'%s\' failed at \'%s\' cut: \'%s\' = %s' % (component['code'], keywords[0], keywords[0], value))
                return False

        # If the keywords do not actually exist for the object, return False too
        except KeyError as error:
            if self.verbose:
                WARNING('Component \'%s\' failed due to KeyError: %s' % (component['code'], error))
            return False
Beispiel #18
0
    def printFetchedList(self):
        '''
        Print a pretty summary of the shipments currently stored in self.json.
        '''

        if self.json == None:
            if self.verbose:
                WARNING(
                    'No shipment list currently fetched from the ITkPD -- nothing printed.'
                )
        else:
            if self.verbose:
                INFO('Printing fetched list of shipments:\n')
            header = [
                'Index', 'ID', 'Shipment Name', 'Sender', 'Recipient',
                'Shipping Service', 'Tracking Number', 'Type', 'Status'
            ]
            format_new = '    {:<10}{:<30}{:<20}{:<15}{:<15}{:<25}{:<20}{:<20}{:<20}'
            print(Colours.BOLD + Colours.WHITE + format_new.format(*header) +
                  Colours.ENDC)
            for i, shipment in enumerate(self.json):
                row = [
                    str(i), shipment['id'], shipment['name'],
                    shipment['sender']['code'], shipment['recipient']['code'],
                    shipment['shippingService'], shipment['trackingNumber'],
                    shipment['type'], shipment['status']
                ]
                print(format_new.format(*row))
            if self.verbose:
                print('')
        return True
Beispiel #19
0
    def printStoredList(self):
        '''
        Print a pretty summary of the shipments currently stored in self.shipments.
        '''

        if self.verbose:
            INFO('Printing stored list of shipments:\n')
        header = [
            'Index', 'ID', 'Shipment Name', 'Sender', 'Recipient',
            'Shipping Service', 'Tracking Number', 'Type', 'Status'
        ]
        format_new = '    {:<10}{:<30}{:<20}{:<15}{:<15}{:<25}{:<20}{:<20}{:<20}'
        print(Colours.BOLD + Colours.WHITE + format_new.format(*header) +
              Colours.ENDC)
        for i, shipment in enumerate(self.shipments):
            row = [
                str(i), shipment.json['id'], shipment.json['name'],
                shipment.json['sender']['code'],
                shipment.json['recipient']['code'],
                shipment.json['shippingService'],
                shipment.json['trackingNumber'], shipment.json['type'],
                shipment.json['status']
            ]
            print(format_new.format(*row))
        if self.verbose:
            print('')
        return True
Beispiel #20
0
    def createAttachment(self, data, title=None, description=None):
        '''
        Create an attachment with binary data and add it to the component.

        Args:
            data (bin str): binary data to be uploaded.
            title (str): the title for the attachment (default: None).
            description (str): the description for the attachment (default: None)
        '''

        # Get our function call kwargs
        kwargs = {
            'component': self.component,
            'title': title,
            'description': description,
            'data': data
        }

        # Generate our dtoIn by removing the items in kwargs which are None
        dtoIn = {k: v for k, v in kwargs.items() if v is not None}

        # Create our attachment and fetch the updated json
        dbCommands['createComponentAttachment'].run(**dtoIn)
        if not self.expert:
            self.get()
            INFO('Attachment code {0} created for component code {1}.'.format(
                self.json['attachments'][-1]['code'], self.component))
        return True
Beispiel #21
0
    def clearShipments(self, *args):
        '''
        Clear stored hipments from self.shipmentss.

        Args:
            args (int): the index(indices) of the shipment(s) in self.shipments to be removed.

        Notes:
            If args == (), then all of the shipments in self.shipments are removed.
            Args that are not integers are ignored
        '''

        if args == ():
            args = range(len(self.shipments))
        else:
            args = [arg for arg in args if isinstance(arg, int)]
        for i in sorted(args, reverse=True):
            try:
                id_current = self.shipments[i].json['id']
                sender_current = self.shipments[i].json['sender']['code']
                recipient_current = self.shipments[i].json['recipient']['code']
                del self.shipments[i]
                if self.verbose:
                    INFO(
                        'Deleted shipment id {0} ({1} --> {2}) from stored list of shipments.'
                        .format(id_current, sender_current, recipient_current))
            except IndexError:
                pass
        return True
Beispiel #22
0
    def getListByInstitution(self, code, status=None):
        '''
        Loads a list of shipments associated with an institution into self.json.

        Args:
            code (list[str]): a list of institution codes to filter shipments by.
            status (list[str]): a list of status codes to filter shipments by. Choose status codes from ['prepared'|'inTransit'|'delivered'|'deliveredWithDamage'|'undelivered'] (default None).

        Notes:
            If code and/or status are given as strings instead of list of strings, those strings are implicitly converted to lists of strings.
        '''

        if not isinstance(code, list):
            code = [code]
        dtoIn = {'code': code, 'status': status}
        if status == None:
            del dtoIn['status']
        else:
            if not isinstance(status):
                status = [status]
            allowed_statuses = [
                'prepared', 'inTransit', 'delivered', 'deliveredWithDamage',
                'undelivered'
            ]
            unknown_statuses = [
                status_item for status_item in status
                if status_item not in allowed_statuses
            ]
            if unknown_statuses != []:
                if self.verbose:
                    WARNING(
                        'Shipping status(es) \'{0}\' is(are) not recognized.'.
                        format('\', \''.join(unknown_statuses)))
                    INFO('No list generated.')
                return False
        self.json = dbCommands['listShipmentsByInstitution'].run(**dtoIn)
        if self.verbose:
            if status == None:
                INFO(
                    'Retrieved list of shipments by institution using code(s) \'{0}\'.'
                    .format('\', \''.join(code)))
            else:
                INFO(
                    'Retrieved list of shipments by component using code(s) \'{0}\' and filtering by status(es) \'{1}\'.'
                    .format('\', \''.join(code), '\', \''.join(status)))
        return True
Beispiel #23
0
    def delete(self):
        '''
        Delete the shipment from the ITkPD.
        '''

        # Delete the shipment
        dbCommands['deleteShipment'].run(shipment=self.shipment)
        if not self.expert:
            INFO('Shipment id {0} deleted.'.format(self.shipment))
        return True
Beispiel #24
0
    def __addCutOnValue(self, cuts, cutName, allowedValues, keywords):

        # Check if allowedValues is a list and doesn't equal a list of None
        # If this passes, we add the cut
        if isinstance(allowedValues, list) and allowedValues != [None]:
            if self.verbose:
                INFO('Adding cut \'%s\'...' % cutName)
            cuts[cutName] = lambda component: self.__cutOnValue(component, allowedValues = allowedValues, keywords = keywords)

        # Check if allowedValues is not a list and doesn't equal None
        # If this passes, we add the cut
        elif not isinstance(allowedValues, list) and allowedValues != None:
            if self.verbose:
                INFO('Adding cut \'%s\'...' % cutName)
            cuts[cutName] = lambda component: self.__cutOnValue(component, allowedValues = allowedValues, keywords = keywords)

        # Else, don't add the cut
        else:
            pass
Beispiel #25
0
    def delete(self):
        '''
        Delete the component from the ITkPD.
        '''

        # Delete the component and fetch the updated json
        dbCommands['deleteComponent'].run(component=self.component)
        if self.expert:
            self.get()
            INFO('Component code {0} deleted.'.format(self.component))
        return True
Beispiel #26
0
    def setCompleted(self, completed):
        '''
        Set the Completed status for the component.

        Args:
            completed (bool): set the component as Completed if True.
        '''

        # Check that completed is a boolean
        if not self.expert and not isinstance(completed, bool):
            WARNING('Completed must be a boolean.')
            INFO('Completed not set.')
            return

        # Set completed and fetch the updated json
        dbCommands['setComponentCompleted'].run(component=self.component,
                                                completed=completed)
        if not self.expert:
            self.get()
            INFO('Completed set to {0} for component code {1}.'.format(
                completed, self.component))
Beispiel #27
0
    def getListByComponent(self, component, status=None):
        '''
        Load a list of shipments associated with a component code into self.json.

        Args:
            code (list[str]): the code for the component to filter shipments by.
            status (list[str]): a status codes to filter shipments by. Choose status codes from ['prepared'|'inTransit'|'delivered'|'deliveredWithDamage'|'undelivered'] (default None).
        '''

        dtoIn = {'component': component, 'status': status}
        if status == None:
            del dtoIn['status']
        else:
            allowed_statuses = [
                'prepared', 'inTransit', 'delivered', 'deliveredWithDamage',
                'undelivered'
            ]
            unknown_statuses = [
                status_item for status_item in status
                if status_item not in allowed_statuses
            ]
            if unknown_statuses != []:
                if self.verbose:
                    WARNING(
                        'Shipping status(es) \'{0}\' not recognized.'.format(
                            '\', \''.join(unknown_statuses)))
                    INFO('No list generated.')
                return False
        self.json = dbCommands['listShipmentsByComponent'].run(**dtoIn)
        if self.verbose:
            if status == None:
                INFO(
                    'Retrieved list of shipments by component using code \'{0}\'.'
                    .format(code))
            else:
                INFO(
                    'Retrieved list of shipments by component using code \'{0}\' and filtering by status(es) \'{1}\'.'
                    .format(code, '\', \''.join(status)))
        return True
Beispiel #28
0
    def __applyCuts(self, component, cuts):

        # Iterate through our cuts
        for cut in cuts.values():

            # If the cut fails (i.e., returns False), return False to indicate that the component did not pass
            if not cut(component):
                return False

        # Else, return True is everything passes
        if self.verbose:
            INFO('Component \'%s\' passed all cuts.' % component['code'])
        return True
Beispiel #29
0
    def printJSON(self):
        '''
        Pretty print the json for the component type.
        '''

        # Pretty print the json
        if not self.expert:
            INFO('Printing JSON for shipment id {0}:\n'.format(self.shipment))
            pp.pprint(self.json)
            print('')
        else:
            pp.pprint(self.json)
        return True
Beispiel #30
0
    def setTrashed(self, trashed):
        '''
        Set the Trashed status for the component.

        Args:
            trashed (bool): set the component as Trashed if True.
        '''

        # Check that trashed is a boolean
        if not self.expert and not isinstance(trashed, bool):
            WARNING('Trashed must be a boolean.')
            INFO('Trashed not set.')
            return False

        # Set trashed and fetch the updated json
        dbCommands['setComponentTrashed'].run(component=self.component,
                                              trashed=trashed)
        if not self.expert:
            self.get()
            INFO('Trashed set to {0} for component code {1}.'.format(
                trashed, self.component))
        return True