Example #1
0
def add_part():
    # add_part adds a new part to the master list of parts
    # user past pass a json with the following fields:
    # name: the name of the new part (string)
    # attributes: the attributes that the part has, such as color
    # or material. It is a list (possibly empty) of strings

    if not request.json or 'name' not in request.json:
        # if the command doesn't include a 'name' field, raise 400 error
        raise InvalidUsage('name field missing from request', status_code=400)

    if not isinstance(request.json['name'], str):
        # if the name isn't a string, raise 400 error
        raise InvalidUsage('name field must be a string', status_code=400)

    if 'attributes' not in request.json:
        attributes = []
    else:
        attributes = api_helper.check_attributes_list(
            request.json['attributes'])

    # figure out the id for the new part
    part_id = api_helper.new_part_id(parts)

    new_part = {
        'id': part_id,
        'name': request.json['name'],
        'children': [],
        'children attribute values': [],
        'attributes': attributes
    }  # create dictionary entry for this new part

    parts.append(new_part)  # append new part to master parts list
    return jsonify({'new part': new_part}), 201
Example #2
0
def remove_children(parent, removal_list):
    # remove_children takes a part's list of current children and
    # removes those in a second list
    # current_list is a list of ids for the current children of this part
    # removal_list is a list of ids to remove

    # make a copy of the current list of parent's children (for modification)
    new_list = parent['children'].copy()
    new_attribute_values = parent['children attribute values'].copy()

    # cycle through the list of child_id to remove,
    # and check to see if it's in current_list
    for child_id in removal_list:
        if child_id in new_list:
            # if child_id is in current_list, remove it and its attributes
            index = new_list.index(child_id)
            new_list.pop(index)
            new_attribute_values.pop(index)
        else:
            # if it's not there, throw a resource not found error
            raise InvalidUsage("Child {0} is not part of this "
                               "assembly".format(str(child_id)),
                               status_code=404)

    return new_list, new_attribute_values
Example #3
0
def get_parts():
    # get_parts returns a list of all parts

    if len(parts) == 0:
        # if no parts, raise 404 error
        raise InvalidUsage('No parts exist', status_code=404)
    return jsonify({'parts': parts})  # return json of parts list
Example #4
0
def get_part(part_id, parts):
    # get_part returns part with id part_id

    # list of all parts that match id
    parts_list = [part for part in parts if part['id'] == part_id]
    if len(parts_list) == 0:
        # if part does not exist, raise 404 error
        raise InvalidUsage('This part does not exist', status_code=404)
    return parts_list[0]
Example #5
0
def add_children(parent, additions_list, attribute_values_list, parts):
    # add_children takes a part's list of current children and a list of
    # additions and combines them.
    # parent is the part to which children are being added.
    # additions_list is a list of ids for the parts to add.
    # attribute_values_list is a list of attribute lists. The first attribute
    # list corresponds to the first child, the second to the second child,
    # etc. An attribute list can be empty if that child has no attributes.
    # For example, if additions_list = [13, 14, 16] and the part with id 13
    # has no attributes, id 14 has 2 attributes, and id 16 has one attribute,
    # attribute_values_list might look like the following:
    # [[], ['red', 'metal'], ['opaque']]
    # parts is a list of all parts

    # make a copy of the current list of parent's children (for modification)
    new_children = parent['children'].copy()
    new_children_attributes = parent['children attribute values'].copy()

    # Cycle through the list of child_id to add, and
    # check to see if we can actually add each one
    for (child_id, attribute_values) in zip(additions_list,
        attribute_values_list):
        # If there's no part with this id, throw a resource not found error
        if not check_part_exists(child_id, parts):
            raise InvalidUsage("Cannot attach part with id {0}; it does not "
                               "exist".format(str(child_id)), status_code=404)

        # As long as the child_id isn't already in the list
        # and isn't equal to the parent_id, it's ok to proceed
        if not (child_id == parent['id'] or child_id in parent['children']):
            # append child_id to the new list of this parent's children
            child = get_part(child_id, parts)
            if type(attribute_values) is not list:
                attribute_values = [attribute_values]

            if not len(child['attributes']) == len(attribute_values):
                raise InvalidUsage("Child with id {0} has wrong number of att"
                                   "ributes".format(child_id), status_code=400)

            new_children.append(child_id)
            new_children_attributes.append(attribute_values)

    return new_children, new_children_attributes
Example #6
0
def get_assemblies():
    # get_assemblies returns a list of all assemblies (parts with children)

    if len(parts) == 0:
        # if no parts, return resource not found
        raise InvalidUsage('No parts exist', status_code=404)

    # find all assemblies -- parts for which the list of children is not empty
    assemblies = [part for part in parts if part['children']]
    return jsonify({'assemblies': assemblies})  # return list as json
Example #7
0
def check_attributes_list(attributes_list):
    # get_attributes_list

    if type(attributes_list) is not list:
        attributes_list = [attributes_list]

    attributes_list_out = []
    for attribute in attributes_list:
        if type(attribute) is not str:
            raise InvalidUsage("Invalid attributes list", status_code=400)
        attributes_list_out.append(attribute)

    return attributes_list_out
Example #8
0
def get_subassemblies():
    # get_sub_assemblies returns a list of all subassemblies (parts that have
    # children and are also themselves children of some other part)

    if len(parts) == 0:
        # if no parts, return resource not found
        raise InvalidUsage('No parts exist', status_code=404)

    # find all  subassemblies -- parts for which the list of children is
    # not empty, and they are children of some other part
    subassemblies = [
        part for part in parts
        if part['children'] and api_helper.is_child(part, parts)
    ]
    return jsonify({'subassemblies': subassemblies})  # return list as json
Example #9
0
def get_orphans():
    # get_orphans returns a list of all orphans
    # (parts that do not have children and are not children of some other part)

    if len(parts) == 0:
        # if no parts, return resource not found
        raise InvalidUsage('No parts exist', status_code=404)

    # find all  orphans -- parts for which the list of children is empty,
    # and they are not children of some other part
    orphans = ([
        part for part in parts
        if not part['children'] and not api_helper.is_child(part, parts)
    ])

    return jsonify({'orphans': orphans})  # return list as json
Example #10
0
def get_components():
    # get_components returns a list of all components (partsthat do
    # not have children but are themselves children of some other part)

    if len(parts) == 0:
        # if no parts, return resource not found
        raise InvalidUsage('No parts exist', status_code=404)

    # find all  components -- parts for which the list of children is empty,
    # and they are children of some other part
    components = ([
        part for part in parts
        if not part['children'] and api_helper.is_child(part, parts)
    ])

    return jsonify({'components': components})  # return list as json
Example #11
0
def get_top_assemblies():
    # get_top_assemblies returns a list of all top level assemblies
    # (parts that have children and are not themselves children)

    if len(parts) == 0:
        # if no parts, return resource not found
        raise InvalidUsage('No parts exist', status_code=404)

    # find all top assemblies -- parts for which the list of children is not
    # empty, and they are not children of some other part
    top_assemblies = ([
        part for part in parts
        if part['children'] and not api_helper.is_child(part, parts)
    ])

    return jsonify({'top assemblies': top_assemblies})  # return list as json
Example #12
0
def delete_part(part_id):
    # delete_part deletes a part from the parts list and from all assemblies
    # part_id is the id number of the part to be deleted

    # list of all parts that match id
    parts_list = [part for part in parts if part['id'] == part_id]
    if len(parts_list) == 0:
        # if the above list is empty, return 404
        raise InvalidUsage('This part does not exist', status_code=404)

    parts.remove(parts_list[0])  # delete the part itself

    # find all instances where it is part of an assembly, and delete
    api_helper.scrub_part(part_id, parts)

    return jsonify({'result': True})
Example #13
0
def get_ancestors(part_id):
    # get_ancestors returns all assemblies that contain the part with id given
    # by part_id. This includes assemblies which contain part_id directly, but
    # also the assemblies that contain those assemblies, etc. all the way up

    if not api_helper.check_part_exists(part_id, parts):
        # if part does not exist, raise 404 error
        raise InvalidUsage('This part does not exist', status_code=404)

    # loop through test_part in parts, and run api_helper.get_all_children_id()
    # on test_part. If part_id is in the list of children for test_part, then
    # test_part goes on the list of ancestors
    ancestors = [
        test_part for test_part in parts
        if part_id in api_helper.get_all_children_id(test_part['id'], parts)
    ]

    return jsonify({'ancestors': ancestors})
Example #14
0
def modify_children(parent_id):
    # modify_children attaches/removes one or more parts to/from a parent part
    # The function below mostly consists of checking for errors, and then the
    # actual addition/removal takes place in helper functions.
    # User mast pass a json with the following fields:
    # action: a string that is either "attach" or "remove"
    # children: a list of the id's of children to attach or remove
    # If children are being attached, there must also be a field
    # "attribute values" which specifies the value of each attribute the
    # children have. It's a list of lists. For example if the children being
    # attached have id's [3, 6, 4] then the first item of "attribute values"
    # is a list of attributes for the part with id 3. If this child with id 3
    # has attributes "color" and "material", then the attribute values list
    # might be ["red", "plastic"]

    parent = api_helper.get_part(parent_id, parts)

    if not request.json:
        # if request is not in json format, error
        raise InvalidUsage('Modification must be in JSON format',
                           status_code=400)

    if 'children' not in request.json:
        # if json request doesn't include a 'children' key, throw an error
        raise InvalidUsage('children field missing from request',
                           status_code=400)

    if 'action' not in request.json:
        # If json request doesn't include an 'action' key, throw an error
        raise InvalidUsage('action field missing from request',
                           status_code=400)

    # Extract list of children to add/remove from json request
    # If the user didn't give the children ids in list form, make it a list
    # Want to allow the case where the user wants to attach/remove a single
    # part, and instead of sending a list of ids just sends the id as an int
    parts_list = request.json['children']
    if type(parts_list) is not list:
        parts_list = [parts_list]

    # call a function to modify the list of children
    # depending on the 'action' keyword
    if request.json['action'] == 'attach':
        # attach children
        # check to make sure there's a list of attribute values, and it
        # is the same length as the list of new children to add
        if 'attribute values' not in request.json:
            raise InvalidUsage('attribute values field missing from request',
                               status_code=400)

        # since attribute values exist, extract from json
        attribute_values = request.json['attribute values']

        # if it's not a list, make it a list
        if type(attribute_values) is not list:
            attribute_values = [attribute_values]
        # if the lengths of the children list and attribute values list
        # don't line up, throw an error
        if not len(attribute_values) == len(parts_list):
            raise InvalidUsage(
                "list of attributes does not match list of "
                "children to add",
                status_code=400)

        # now that these checks have been done, can actually add children
        new_children_list, new_children_attributes_list = api_helper.add_children(
            parent, parts_list, attribute_values, parts)
    elif request.json['action'] == 'remove':
        # remove children
        new_children_list, new_children_attributes_list = api_helper.remove_children(
            parent, parts_list)
    else:
        raise InvalidUsage('action field must specify attach or remove',
                           status_code=400)

    # modify the list of children, but first create a copy of the current
    # list, in case we have to revert after checking for loops
    old_children_list = parent['children'].copy()
    parent['children'] = new_children_list

    if api_helper.check_loops(parts):
        # check to see if any loops have been created
        # if so, revert to the old list of children and raise error
        parent['children'] = old_children_list
        raise InvalidUsage(
            "Cannot add parts to assembly, as it creates an "
            "infinite loop",
            status_code=409)

    parent['children attribute values'] = new_children_attributes_list
    return jsonify({'assembly': parent})