예제 #1
0
    def sortListedObjects(objList, template):
        sortedObjList = []
        for obj in objList:
            sortedObj = {key: obj[key] for key in template if key in obj}
            sortedObj.update(obj)
            sortedObjList.append(sortedObj)

        if len(objList) != len(sortedObjList):
            return objList
        for obj, sobj in zip(objList, sortedObjList):
            if obj != sobj:
                print_warning("Sorted list does not represent"
                              " original list.")
                return objList
        return sortedObjList
예제 #2
0
def customSortInvocationByInput(invocation, descriptor):
    descriptor = loadJson(descriptor)
    # sort invoc according to input's order in decsriptor
    sortedInvoc = {
        key: invocation[key]
        for key in [
            inp['id'] for inp in descriptor['inputs']
            if descriptor['inputs'] is not None
        ] if key in invocation
    }
    if sortedInvoc != invocation:
        print_warning("Sorted invocation does not represent"
                      " original invocation.")
        return invocation
    return sortedInvoc
예제 #3
0
def customSortDescriptorByKey(descriptor,
                              template=os.path.join(os.path.dirname(bfile),
                                                    "templates",
                                                    "ordered_keys_desc.json")):
    def sortListedObjects(objList, template):
        sortedObjList = []
        for obj in objList:
            sortedObj = {key: obj[key] for key in template if key in obj}
            sortedObj.update(obj)
            sortedObjList.append(sortedObj)

        if len(objList) != len(sortedObjList):
            return objList
        for obj, sobj in zip(objList, sortedObjList):
            if obj != sobj:
                print_warning("Sorted list does not represent"
                              " original list.")
                return objList
        return sortedObjList

    template = loadJson(template)
    sortedDesc = {}
    # Add k:v to sortedDesc according to their order in template
    for key in [k for k in template if k in descriptor]:
        if type(descriptor[key]) is list:
            sortedDesc[key] =\
                sortListedObjects(descriptor[key], template[key][0])
        else:
            sortedDesc[key] = descriptor[key]

    # Add remaining k:v that are missing from template
    sortedDesc.update(descriptor)
    if sortedDesc != descriptor:
        print_warning("Sorted descriptor does not represent"
                      " original descriptor.")
        return descriptor
    return sortedDesc
예제 #4
0
def deprecate(zenodo_id,
              by_zenodo_id=None,
              sandbox=False,
              verbose=False,
              zenodo_token=None,
              download_function=urlretrieve):

    # Get the descriptor and Zenodo id
    puller = Puller([zenodo_id], verbose=verbose, sandbox=sandbox)
    descriptor_fname = puller.pull()[0]
    descriptor_json = loadJson(descriptor_fname,
                               sandbox=sandbox,
                               verbose=verbose)

    # Return if tool is already deprecated
    deprecated = descriptor_json.get('deprecated-by-doi')
    if deprecated is not None:
        if isinstance(deprecated, str):
            print_info('Tool {0} is already deprecated by {1} '.format(
                zenodo_id, deprecated))
        if by_zenodo_id is not None:
            prompt = ("Tool {0} will be deprecated by {1}, "
                      "this cannot be undone. Are you sure? (Y/n) ")\
                          .format(zenodo_id, by_zenodo_id)
            ret = input(prompt)
            if ret.upper() != "Y":
                return
        else:
            print_warning('Tool {0} is already deprecated'.format(zenodo_id))
            return
    # Set record id and Zenodo id
    zhelper = ZenodoHelper(sandbox=sandbox, no_int=True, verbose=verbose)
    zid = zhelper.get_zid_from_filename(descriptor_fname)
    record_id = zhelper.get_record_id_from_zid(zid)

    # Return if tool has a newer version
    record = zhelper.zenodo_get_record(record_id)
    if not record['metadata']['relations']['version'][0]['is_last']:
        new_version = (record['metadata']['relations']['version'][0]
                       ['last_child']['pid_value'])
        raise_error(
            DeprecateError, 'Tool {0} has a newer version '
            '(zenodo.{1}), it cannot be deprecated.'.format(
                zenodo_id, new_version))
        return

    # Add deprecated property
    if by_zenodo_id is None:
        descriptor_json['deprecated-by-doi'] = True
    else:
        # Check that by_zenodo_id exists
        by_record_id = zhelper.get_record_id_from_zid(by_zenodo_id)
        if zhelper.record_exists(by_record_id) is False:
            raise_error(DeprecateError,
                        "Tool does not exist: {0}".format(by_zenodo_id))
        # Assign deprecated-by property
        by_doi_id = zhelper.get_doi_from_zid(by_zenodo_id)
        descriptor_json['deprecated-by-doi'] = by_doi_id

    # Add doi to descriptor (mandatory for update)
    if descriptor_json.get('doi') is None:
        descriptor_json['doi'] = zhelper.get_doi_from_zid(zid)

    # Save descriptor in temp file
    tmp = tempfile.NamedTemporaryFile(delete=False, mode='w', suffix=".json")
    content = json.dumps(descriptor_json, indent=4, sort_keys=True)
    tmp.write(content)
    tmp.close()

    # Publish updated descriptor
    publisher = Publisher(tmp.name,
                          zenodo_token,
                          replace=True,
                          sandbox=sandbox,
                          no_int=True,
                          id="zenodo." + zid,
                          verbose=verbose)
    return publisher.publish()
예제 #5
0
    def parseAction(self, action, **kwargs):
        # Case 1: input is a help flag
        # Desired outcome: we skip it
        if type(action) is argparse._HelpAction:
            if kwargs.get("verbose"):
                print_info("_HelpAction: Skipping")
            # If this action belongs to a subparser, return a flag alongside
            # the empty object, indicating it is not required
            if kwargs.get("subaction"):
                return {}, False
            return {}

        # Case 2: input is a subparser
        # Desired outcome: we add the subparser and options, and an input for
        # each of the subparser options
        elif (type(action) is argparse._SubParsersAction
              and not kwargs.get("addParser")):
            if kwargs.get("verbose"):
                print_info("_SubParsersAction: Interpretting & Adding")

            # First, add the subparser itself as an input.
            subparser = self.parseAction(action, addParser=True)
            subparser["value-requires"] = {}
            inpts = {}
            # For every option specified by the subparser...
            for act in subparser["value-choices"]:
                inpts[act] = []
                subparser["value-requires"][act] = []
                # ... And for each choice specified by each subparser...
                for subact in action.choices[act]._actions:

                    # Process the action, and record its "required" status
                    tmpinput, reqd = self.parseAction(subact,
                                                      subaction=True,
                                                      **kwargs)

                    # If it's not empty, add it to an inputs dictionaryi, and
                    # add the input to the descriptor.
                    if tmpinput != {}:
                        inpts[act] += [tmpinput["id"]]
                        # If the input was required by the subparser, record it
                        if reqd:
                            subparser["value-requires"][act] += [
                                tmpinput["id"]
                            ]
                        self.descriptor["inputs"] += [tmpinput]

            # Once all subparsers are processed, identify which inputs need to
            # be disabled by which subparsers.
            inpt_ids = set([inp for iact in inpts for inp in inpts[iact]])
            subparser["value-disables"] = {}
            for act in subparser["value-choices"]:
                # Add all IDs created by the subparser that do not also belong
                # to the current selection to the disabled list.
                subparser["value-disables"][act] = [
                    ckey for ckey in inpt_ids if ckey not in inpts[act]
                ]
            return subparser

        # Case 3: input is a regular input
        # Desired outcome: we add it, unless it's already been added
        else:
            if kwargs.get("verbose"):
                actstring = str(type(action))
                actstring = actstring.split("'")[1].split(".")[-1]
                print_info("{0}: Adding".format(actstring))
            actdict = vars(action)
            if action.dest == "==SUPPRESS==":
                adest = "subparser_{0}".format(self.sp_count)
                if kwargs.get("verbose"):
                    print_warning("Subparser has no destination set, "
                                  "invocation parsing may not work as "
                                  "expected. This can be fixed by adding "
                                  "\"dest='mysubparser'\" to subparser "
                                  "creation.")
                self.sp_count += 1
            else:
                adest = action.dest

            # If an input already exists with this ID, don't re-add it
            if any(adest == it["id"] for it in self.descriptor["inputs"]):
                if kwargs.get("verbose"):
                    print_info("Duplicate: Argument won't be added multiple "
                               "times ({0})".format(adest))
                # If this action belongs to a subparser return a flag alongside
                # the empty object, indicating it is not required
                if kwargs.get("subaction"):
                    return {}, False
                return {}

            # If no argument exists yet by this name, process and add it.
            # First, by setting some reasonable defaults or obvious values,
            # and then by updating others.
            newinput = {
                "id": adest,
                "name": adest,
                "description": action.help,
                "optional": kwargs.get("subaction") or not action.required,
                "type": "String",
                "value-key": "[{0}]".format(adest.upper().strip("[]"))
            }

            if action.type is not None:
                if action.type in [int, float]:
                    newinput["type"] = "Number"
                if action.type == list:
                    newinput["list"] = True

            if action.nargs is not None:
                if ((isinstance(action.nargs, str) and action.nargs == "+") or
                    (isinstance(action.nargs, int) and action.nargs > 1)):
                    newinput["list"] = True

            if action.default:
                newinput["default-value"] = action.default

            if action.choices:
                try:
                    # Subparsers have choices in the form of OrderedDicts...
                    newinput["value-choices"] = list(action.choices.keys())
                except AttributeError as e:
                    # ... but "choice" inputs have them in the form a list.
                    newinput["value-choices"] = action.choices

            if len(action.option_strings):
                newinput["command-line-flag"] = action.option_strings[0]

            if type(action) is argparse._StoreTrueAction:
                newinput["type"] = "Flag"

            self.descriptor["command-line"] += " [{0}]".format(
                adest.upper().strip("[]"))
            # If this action belongs to a subparser, return a flag along
            # with the object, indicating its required/not required status.
            if kwargs.get("subaction"):
                return newinput, action.required
            return newinput