def test_mutually_exclusive_groups(self): script_path = os.path.join(self.script_dir, 'mutually_exclusive.py') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ { 'model': 'BooleanField', 'type': 'checkbox', 'mutex_group': {'id': 0, 'title': None}, 'name': 'foo', 'required': False, 'help': None, 'param': '--foo', 'param_action': set(), 'choices': None, 'choice_limit': 0, 'checked': False, }, { 'model': 'BooleanField', 'type': 'checkbox', 'mutex_group': {'id': 0, 'title': None}, 'name': 'bar', 'required': False, 'help': None, 'param': '--bar', 'param_action': set(), 'choices': None, 'choice_limit': 0, 'checked': True, }, { 'model': 'BooleanField', 'type': 'checkbox', 'mutex_group': {'id': 1, 'title': None}, 'name': 'foo2', 'required': False, 'help': None, 'param': '--foo2', 'param_action': set(), 'choices': None, 'choice_limit': 0, 'checked': False, }, { 'model': 'BooleanField', 'type': 'checkbox', 'mutex_group': {'id': 1, 'title': None}, 'name': 'bar2', 'required': False, 'help': None, 'param': '--bar2', 'param_action': set(), 'choices': None, 'choice_limit': 0, 'checked': True, }, ], 'group': 'optional arguments', }, )
def test_argparse_specify_every_param(self): script_path = os.path.join(self.script_dir, 'choices.py') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertEqual(script_params['path'], script_path) append_field = [i for i in script_params['inputs'][''][1]['nodes'] if i['param'] == '--need-at-least-one-numbers'][0] self.assertIn(SPECIFY_EVERY_PARAM, append_field['param_action'])
def add_wooey_script(script=None, group=None): from ..models import Script, ScriptGroup, ScriptParameter, ScriptParameterGroup # if we have a script, it will at this point be saved in the model pointing to our file system, which may be # ephemeral. So the path attribute may not be implemented if not isinstance(script, six.string_types): try: script_path = script.script_path.path except NotImplementedError: script_path = script.script_path.name script_obj, script = (script, get_storage_object(script_path, local=True).path) if isinstance(script, Script) else (False, script) if isinstance(group, ScriptGroup): group = group.group_name if group is None: group = 'Wooey Scripts' basename, extension = os.path.splitext(script) filename = os.path.split(basename)[1] parser = Parser(script_name=filename, script_path=script) if not parser.valid: return (False, parser.error) # make our script d = parser.get_script_description() script_group, created = ScriptGroup.objects.get_or_create(group_name=group) if script_obj is False: wooey_script, created = Script.objects.get_or_create(script_group=script_group, script_description=d['description'], script_path=script, script_name=d['name']) else: created = False if not script_obj.script_description: script_obj.script_description = d['description'] if not script_obj.script_name: script_obj.script_name = d['name'] # probably a much better way to avoid this recursion script_obj._add_script = False script_obj.save() if not created: if script_obj is False: wooey_script.script_version += 1 wooey_script.save() if script_obj: wooey_script = script_obj # make our parameters for param_group_info in d['inputs']: param_group, created = ScriptParameterGroup.objects.get_or_create(group_name=param_group_info.get('group'), script=wooey_script) for param in param_group_info.get('nodes'): # TODO: fix 'file' to be global in argparse is_out = True if param.get('upload', None) is False and param.get('type') == 'file' else not param.get('upload', False) script_param, created = ScriptParameter.objects.get_or_create(script=wooey_script, short_param=param['param'], script_param=param['name'], is_output=is_out, required=param.get('required', False), form_field=param['model'], default=param.get('default'), input_type=param.get('type'), choices=json.dumps(param.get('choices')), choice_limit=json.dumps(param.get('choice_limit', 1)), param_help=param.get('help'), is_checked=param.get('checked', False), parameter_group=param_group) # update our loaded scripts load_scripts() return (True, '')
def test_subparser(self): script_path = os.path.join(self.script_dir, 'subparser_script.py') parser = Parser(script_path=script_path) description = parser.get_script_description() main_parser = description['inputs'][''] main_parser_group1 = main_parser[0] self.assertEqual(main_parser_group1['nodes'][0]['name'], 'test_arg') self.assertEqual(main_parser_group1['group'], 'optional arguments') subparser1 = description['inputs']['subparser1'] subparser_group1 = subparser1[0] self.assertEqual(subparser_group1['nodes'][0]['name'], 'sp1')
def test_zipapp(self): script_path = os.path.join(self.script_dir, 'data_reader.zip') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ {'param_action': set([]), 'name': 'n', 'required': False, 'param': '-n', 'choices': None, 'value': -1, 'choice_limit': None, 'model': 'IntegerField', 'type': 'text', 'help': 'The number of rows to read.'}], 'group': 'optional arguments', } )
def test_zipapp(self): script_path = os.path.join(self.script_dir, 'data_reader.zip') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ {'param_action': set([]), 'name': 'n', 'required': False, 'param': '-n', 'choices': None, 'value': -1, 'choice_limit': None, 'model': 'IntegerField', 'type': 'text', 'help': 'The number of rows to read.', 'mutex_group': {},}], 'group': 'optional arguments', } )
def test_error_script(self): script_path = os.path.join(self.script_dir, 'error_script.py') parser = Parser(script_path=script_path) if PY_MINOR_VERSION >= PY36: self.assertIn('ModuleNotFoundError', parser.error) else: self.assertIn('ImportError', parser.error) self.assertIn('something_i_dont_have', parser.error) script_path = os.path.join(self.script_dir, 'choices.py') parser = Parser(script_path=script_path) self.assertEquals('', parser.error)
def test_function_type_script(self): script_path = os.path.join(self.script_dir, 'function_argtype.py') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertEqual(script_params['path'], script_path) self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ { 'param_action': set([]), 'name': 'start_date', 'required': True, 'param': '', 'choices': None, 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': 'Use date in format YYYYMMDD (e.g. 20180131)', # The default argument 'value': '20180131', 'mutex_group': {}, }, { 'param_action': set([]), 'name': 'lowercase', 'required': True, 'param': '', 'choices': None, 'value': 'ABC', 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': 'Lowercase it', 'mutex_group': {}, } ], 'group': 'positional arguments' } )
def test_function_type_script(self): script_path = os.path.join(self.script_dir, 'function_argtype.py') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertEqual(script_params['path'], script_path) self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ { 'param_action': set([]), 'name': 'start_date', 'required': True, 'param': '', 'choices': None, 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': 'Use date in format YYYYMMDD (e.g. 20180131)', # The default argument 'value': '20180131' }, { 'param_action': set([]), 'name': 'lowercase', 'required': True, 'param': '', 'choices': None, 'value': 'ABC', 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': 'Lowercase it' } ], 'group': 'positional arguments' } )
def test_naval_fate(self): script_path = os.path.join(self.script_dir, 'naval_fate.py') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertEqual(script_params['path'], script_path) self.assertEqual(script_params['name'], 'naval_fate') # Make sure we return parameters in the order the script defined them and in groups # We do not test this that exhaustively atm since the structure is likely to change when subparsers # are added self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ {'model': 'CharField', 'type': 'text', 'name': 'speed', 'param': '--speed'}, {'model': 'BooleanField', 'type': 'checkbox', 'name': 'moored', 'param': '--moored'}, {'model': 'BooleanField', 'type': 'checkbox', 'name': 'drifting', 'param': '--drifting'} ], 'group': 'default' } )
def test_argparse_script(self): script_path = os.path.join(self.script_dir, 'choices.py') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertEqual(script_params['path'], script_path) # Make sure we return parameters in the order the script defined them and in groups # We do not test this that exhaustively atm since the structure is likely to change when subparsers # are added self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ {'param_action': set([]), 'name': 'first_pos', 'required': True, 'param': '', 'choices': None, 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': None, 'mutex_group': {},}, {'param_action': set([]), 'name': 'second-pos', 'required': True, 'param': '', 'choices': None, 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': None, 'mutex_group': {},} ], 'group': 'positional arguments' } )
def test_argparse_script(self): script_path = os.path.join(self.script_dir, 'choices.py') parser = Parser(script_path=script_path) script_params = parser.get_script_description() self.assertEqual(script_params['path'], script_path) # Make sure we return parameters in the order the script defined them and in groups # We do not test this that exhaustively atm since the structure is likely to change when subparsers # are added self.assertDictEqual( script_params['inputs'][''][0], { 'nodes': [ {'param_action': set([]), 'name': 'first_pos', 'required': True, 'param': '', 'choices': None, 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': None}, {'param_action': set([]), 'name': 'second-pos', 'required': True, 'param': '', 'choices': None, 'choice_limit': None, 'model': 'CharField', 'type': 'text', 'help': None} ], 'group': 'positional arguments' } )
def add_wooey_script(script_version=None, script_path=None, group=None, script_name=None): # There is a class called 'Script' which contains the general information about a script. However, that is not where the file details # of the script lie. That is the ScriptVersion model. This allows the end user to tag a script as a favorite/etc. and set # information such as script descriptions/names that do not constantly need to be updated with every version change. Thus, # a ScriptVersion stores the file info and such. from ..models import Script, ScriptGroup, ScriptParser, ScriptParameter, ScriptParameterGroup, ScriptVersion # if we are adding through the admin, at this point the file will be saved already and this method will be receiving # the scriptversion object. Otherwise, we are adding through the managementment command. In this case, the file will be # a location and we need to setup the Script and ScriptVersion in here. # check if the script exists script_path = script_path or script_version.script_path.name script_name = script_name or (script_version.script.script_name if script_version else os.path.basename( os.path.splitext(script_path)[0])) with get_storage_object(script_path) as so: checksum = get_checksum(buff=so.read()) existing_version = None try: existing_version = ScriptVersion.objects.get( checksum=checksum, script__script_name=script_name) except ObjectDoesNotExist: pass except MultipleObjectsReturned: # This exists because previous versions did not enforce a checksum, so multiple scriptverisons are # possible with the same checksum. existing_version = ScriptVersion.objects.filter( checksum=checksum, script__script_name=script_name).order_by( 'script_version', 'script_iteration').last() # If script_verison is None, it likely came from `addscript` if existing_version is not None and (script_version is None or existing_version != script_version): return { 'valid': False, 'errors': errors.DuplicateScriptError( ScriptVersion.error_messages['duplicate_script']), 'script': existing_version, } local_storage = get_storage(local=True) if script_version is not None: # we are updating the script here or creating it through the admin # we need to move the script to the wooey scripts directory now # handle remotely first, because by default scripts will be saved remotely if we are using an # ephemeral file system old_name = script_version.script_path.name new_name = os.path.normpath( os.path.join(wooey_settings.WOOEY_SCRIPT_DIR, old_name) if not old_name.startswith(wooey_settings.WOOEY_SCRIPT_DIR) else old_name) current_storage = get_storage( local=not wooey_settings.WOOEY_EPHEMERAL_FILES) current_file = current_storage.open(old_name) if current_storage.exists(new_name): new_name = current_storage.get_available_name(new_name) new_path = current_storage.save(new_name, current_file) # remove the old file if old_name != new_name: current_file.close() current_storage.delete(old_name) current_file = current_storage.open(new_path) script_version._rename_script = True script_version.script_path.name = new_name script_version.save() # download the script locally if it doesn't exist if not local_storage.exists(new_path): new_path = local_storage.save(new_path, current_file) # Close the old file if it is not yet if not current_file.closed: current_file.close() with get_storage_object(new_path, local=True) as so: script = so.path with local_storage.open(new_path) as local_handle: local_file = local_handle.name else: # we got a path, if we are using a remote file system, it will be located remotely by default # make sure we have it locally as well if wooey_settings.WOOEY_EPHEMERAL_FILES: remote_storage = get_storage(local=False) with remote_storage.open(script_path) as remote_file: local_file = local_storage.save(script_path, remote_file) else: with local_storage.open(script_path) as local_handle: local_file = local_handle.name with get_storage_object(local_file, local=True) as so: script = so.path if isinstance(group, ScriptGroup): group = group.group_name if group is None: group = 'Wooey Scripts' basename, extension = os.path.splitext(script) filename = os.path.split(basename)[1] parser = Parser(script_name=filename, script_path=local_storage.path(local_file)) if not parser.valid: return { 'valid': False, 'errors': errors.ParserError(parser.error), } # make our script script_schema = parser.get_script_description() script_group, created = ScriptGroup.objects.get_or_create(group_name=group) version_string = script_schema.get('version') if version_string is None: version_string = '1' try: parse_version(version_string) except: sys.stderr.write( 'Error parsing version, defaulting to 1. Error message:\n {}'. format(traceback.format_exc())) version_string = '1' if script_version is None: # we are being loaded from the management command, create/update our script/version script_kwargs = { 'script_group': script_group, 'script_name': script_name or script_schema['name'] } version_kwargs = { 'script_version': version_string, 'script_path': local_file, 'default_version': True, 'checksum': checksum } # does this script already exist in the database? script_created = Script.objects.filter(**script_kwargs).count() == 0 if script_created: # we are creating it, add the description if we can script_kwargs.update( {'script_description': script_schema['description']}) wooey_script = Script(**script_kwargs) wooey_script._script_cl_creation = True wooey_script.save() version_kwargs.update({'script_iteration': 1}) else: # we're updating it wooey_script = Script.objects.get(**script_kwargs) if not wooey_script.script_description and script_schema[ 'description']: wooey_script.script_description = script_schema['description'] wooey_script.save() # check if we have the version in our script version current_versions = ScriptVersion.objects.filter( script=wooey_script, script_version=version_string) if current_versions.count() == 0: next_iteration = 1 else: # get the largest iteration and add 1 to it next_iteration = sorted( [i.script_iteration for i in current_versions])[-1] + 1 # disable older versions ScriptVersion.objects.filter(script=wooey_script).update( default_version=False) version_kwargs.update({'script_iteration': next_iteration}) version_kwargs.update({'script': wooey_script}) script_version = ScriptVersion(**version_kwargs) script_version._script_cl_creation = True script_version.checksum = checksum script_version.save() else: # we are being created/updated from the admin wooey_script = script_version.script if not wooey_script.script_description: wooey_script.script_description = script_schema['description'] if not wooey_script.script_name: wooey_script.script_name = script_name or script_schema['name'] past_versions = ScriptVersion.objects.filter( script=wooey_script, script_version=version_string).exclude(pk=script_version.pk) if len(past_versions) == 0: script_version.script_version = version_string script_version.script_iteration = past_versions.count() + 1 # Make all old versions non-default ScriptVersion.objects.filter(script=wooey_script).update( default_version=False) script_version.default_version = True script_version.checksum = checksum wooey_script.save() script_version.save() # make our parameters parameter_index = 0 for parser_name, parser_inputs in six.iteritems(script_schema['inputs']): parsers = ScriptParser.objects.filter( name=parser_name, script_version__script=wooey_script).distinct() if len(parsers): parser = parsers.first() else: parser = ScriptParser.objects.create(name=parser_name, ) parser.save() parser.script_version.add(script_version) for param_group_info in parser_inputs: param_group_name = param_group_info.get('group') param_groups = ScriptParameterGroup.objects.filter( group_name=param_group_name, script_version__script=wooey_script).distinct() # TODO: There should only ever be one, should probably do a harder enforcement of this. if len(param_groups): param_group = param_groups.first() else: param_group = ScriptParameterGroup.objects.create( group_name=param_group_name, ) param_group.save() param_group.script_version.add(script_version) for param in param_group_info.get('nodes'): # TODO: fix 'file' to be global in argparse is_out = True if (param.get('upload', None) == False and param.get('type') == 'file' ) else not param.get('upload', False) script_param_kwargs = { 'short_param': param['param'], 'script_param': param['name'], 'is_output': is_out, 'required': param.get('required', False), 'form_field': param['model'], 'default': param.get('value'), 'input_type': param.get('type'), 'choices': json.dumps(param.get('choices')), 'choice_limit': json.dumps(param.get('choice_limit', 1)), 'param_help': param.get('help'), 'is_checked': param.get('checked', False), # parameter_group': param_group, 'collapse_arguments': SPECIFY_EVERY_PARAM not in param.get('param_action', set()), } parameter_index += 1 # This indicates the parameter is a positional argument. If these are changed between script versions, # the script can break. Therefore, we have to add an additional filter on the parameter order that # keyword arguments can ignore. if not param['param']: script_param_kwargs['param_order'] = parameter_index script_params = ScriptParameter.objects.filter( **script_param_kwargs).filter( script_version__script=wooey_script, parameter_group__group_name=param_group_name, parser__name=parser_name).distinct() if not script_params: script_param_kwargs['parser'] = parser script_param_kwargs['parameter_group'] = param_group if 'param_order' not in script_param_kwargs: script_param_kwargs['param_order'] = parameter_index script_param, created = ScriptParameter.objects.get_or_create( **script_param_kwargs) script_param.script_version.add(script_version) else: # If we are here, the script parameter exists and has not changed since the last update. We can simply # point the new script at the old script parameter. This lets us clone old scriptversions and have their # parameters still auto populate. script_param = script_params[0] if 'param_order' not in script_param_kwargs: script_param.param_order = parameter_index script_param.script_version.add(script_version) script_param.save() return { 'valid': True, 'errors': None, 'script': script_version, }
def add_wooey_script(script_version=None, script_path=None, group=None): # There is a class called 'Script' which contains the general information about a script. However, that is not where the file details # of the script lie. That is the ScriptVersion model. This allows the end user to tag a script as a favorite/etc. and set # information such as script descriptions/names that do not constantly need to be updated with every version change. Thus, # a ScriptVersion stores the file info and such. from ..models import Script, ScriptGroup, ScriptParameter, ScriptParameterGroup, ScriptVersion # if we are adding through the admin, at this point the file will be saved already and this method will be receiving # the scriptversion object. Otherwise, we are adding through the managementment command. In this case, the file will be # a location and we need to setup the Script and ScriptVersion in here. local_storage = get_storage(local=True) if script_version is not None: # we are updating the script here or creating it through the admin # we need to move the script to the wooey scripts directory now # handle remotely first, because by default scripts will be saved remotely if we are using an # ephemeral file system old_name = script_version.script_path.name new_name = os.path.normpath( os.path.join(wooey_settings.WOOEY_SCRIPT_DIR, old_name) if not old_name.startswith(wooey_settings.WOOEY_SCRIPT_DIR) else old_name) current_storage = get_storage( local=not wooey_settings.WOOEY_EPHEMERAL_FILES) current_file = current_storage.open(old_name) if current_storage.exists(new_name): new_name = current_storage.get_available_name(new_name) new_path = current_storage.save(new_name, current_file) # remove the old file if old_name != new_name: current_file.close() current_storage.delete(old_name) current_file = current_storage.open(new_path) script_version._rename_script = True script_version.script_path.name = new_name script_version.save() # download the script locally if it doesn't exist if not local_storage.exists(new_path): new_path = local_storage.save(new_path, current_file) script = get_storage_object(new_path, local=True).path local_file = local_storage.open(new_path).name else: # we got a path, if we are using a remote file system, it will be located remotely by default # make sure we have it locally as well if wooey_settings.WOOEY_EPHEMERAL_FILES: remote_storage = get_storage(local=False) remote_file = remote_storage.open(script_path) local_file = local_storage.save(script_path, remote_file) else: local_file = local_storage.open(script_path).name script = get_storage_object(local_file, local=True).path if isinstance(group, ScriptGroup): group = group.group_name if group is None: group = 'Wooey Scripts' basename, extension = os.path.splitext(script) filename = os.path.split(basename)[1] parser = Parser(script_name=filename, script_path=local_storage.path(local_file)) if not parser.valid: return {'valid': False, 'errors': parser.error} # make our script d = parser.get_script_description() script_group, created = ScriptGroup.objects.get_or_create(group_name=group) version_string = d.get('version') if version_string is None: version_string = '1' try: parse_version(version_string) except: sys.stderr.write( 'Error parsing version, defaulting to 1. Error message:\n {}'. format(traceback.format_exc())) version_string = '1' if script_version is None: # we are being loaded from the management command, create/update our script/version script_kwargs = { 'script_group': script_group, 'script_name': d['name'] } version_kwargs = { 'script_version': version_string, 'script_path': local_file, 'default_version': True } # does this script already exist in the database? script_created = Script.objects.filter(**script_kwargs).count() == 0 if script_created: # we are creating it, add the description if we can script_kwargs.update({'script_description': d['description']}) wooey_script = Script(**script_kwargs) wooey_script._script_cl_creation = True wooey_script.save() version_kwargs.update({'script_iteration': 1}) else: # we're updating it wooey_script = Script.objects.get(**script_kwargs) if not wooey_script.script_description and d['description']: wooey_script.script_description = d['description'] wooey_script.save() # check if we have the version in our script version current_versions = ScriptVersion.objects.filter( script=wooey_script, script_version=version_string) if current_versions.count() == 0: next_iteration = 1 # disable older versions ScriptVersion.objects.filter( script=wooey_script, script_version=version_string).update( default_version=False) else: # get the largest iteration and add 1 to it next_iteration = sorted( [i.script_iteration for i in current_versions])[-1] + 1 version_kwargs.update({'script_iteration': next_iteration}) version_kwargs.update({'script': wooey_script}) script_version = ScriptVersion(**version_kwargs) script_version._script_cl_creation = True script_version.save() else: # we are being created/updated from the admin if not script_version.script.script_description: script_version.script.script_description = d['description'] if not script_version.script.script_name: script_version.script.script_name = d['name'] past_versions = ScriptVersion.objects.filter( script=script_version.script, script_version=version_string).exclude(pk=script_version.pk) script_version.script_iteration = past_versions.count() + 1 past_versions.update(default_version=False) script_version.default_version = True script_version.script.save() script_version.save() # make our parameters for param_group_info in d['inputs']: param_group, created = ScriptParameterGroup.objects.get_or_create( group_name=param_group_info.get('group'), script_version=script_version) for param in param_group_info.get('nodes'): # TODO: fix 'file' to be global in argparse is_out = True if param.get('upload', None) is False and param.get( 'type') == 'file' else not param.get('upload', False) script_param, created = ScriptParameter.objects.get_or_create( script_version=script_version, short_param=param['param'], script_param=param['name'], is_output=is_out, required=param.get('required', False), form_field=param['model'], default=param.get('value'), input_type=param.get('type'), choices=json.dumps(param.get('choices')), choice_limit=json.dumps(param.get('choice_limit', 1)), param_help=param.get('help'), is_checked=param.get('checked', False), parameter_group=param_group) return {'valid': True, 'errors': None, 'script': script_version}
def add_wooey_script(script_version=None, script_path=None, group=None): # There is a class called 'Script' which contains the general information about a script. However, that is not where the file details # of the script lie. That is the ScriptVersion model. This allows the end user to tag a script as a favorite/etc. and set # information such as script descriptions/names that do not constantly need to be updated with every version change. Thus, # a ScriptVersion stores the file info and such. from ..models import Script, ScriptGroup, ScriptParameter, ScriptParameterGroup, ScriptVersion # if we are adding through the admin, at this point the file will be saved already and this method will be receiving # the scriptversion object. Otherwise, we are adding through the managementment command. In this case, the file will be # a location and we need to setup the Script and ScriptVersion in here. local_storage = get_storage(local=True) if script_version is not None: # we are updating the script here or creating it through the admin # we need to move the script to the wooey scripts directory now # handle remotely first, because by default scripts will be saved remotely if we are using an # ephemeral file system old_name = script_version.script_path.name new_name = os.path.normpath(os.path.join(wooey_settings.WOOEY_SCRIPT_DIR, old_name) if not old_name.startswith(wooey_settings.WOOEY_SCRIPT_DIR) else old_name) current_storage = get_storage(local=not wooey_settings.WOOEY_EPHEMERAL_FILES) current_file = current_storage.open(old_name) if current_storage.exists(new_name): new_name = current_storage.get_available_name(new_name) new_path = current_storage.save(new_name, current_file) # remove the old file if old_name != new_name: current_storage.delete(old_name) script_version._rename_script = True script_version.script_path.name = new_name script_version.save() # download the script locally if it doesn't exist if not local_storage.exists(new_path): new_path = local_storage.save(new_path, current_file) script = get_storage_object(new_path, local=True).path local_file = local_storage.open(new_path).name else: # we got a path, if we are using a remote file system, it will be located remotely by default # make sure we have it locally as well if wooey_settings.WOOEY_EPHEMERAL_FILES: remote_storage = get_storage(local=False) remote_file = remote_storage.open(script_path) local_file = local_storage.save(script_path, remote_file) else: local_file = local_storage.open(script_path).name script = get_storage_object(local_file, local=True).path if isinstance(group, ScriptGroup): group = group.group_name if group is None: group = 'Wooey Scripts' basename, extension = os.path.splitext(script) filename = os.path.split(basename)[1] parser = Parser(script_name=filename, script_path=local_storage.path(local_file)) if not parser.valid: return {'valid': False, 'errors': parser.error} # make our script d = parser.get_script_description() script_group, created = ScriptGroup.objects.get_or_create(group_name=group) version_string = d.get('version') if version_string is None: version_string = '1' try: parse_version(version_string) except: sys.stderr.write('Error parsing version, defaulting to 1. Error message:\n {}'.format(traceback.format_exc())) version_string = '1' if script_version is None: # we are being loaded from the management command, create/update our script/version script_kwargs = {'script_group': script_group, 'script_name': d['name']} version_kwargs = {'script_version': version_string, 'script_path': local_file, 'default_version': True} # does this script already exist in the database? script_created = Script.objects.filter(**script_kwargs).count() == 0 if script_created: # we are creating it, add the description if we can script_kwargs.update({'script_description': d['description']}) wooey_script = Script(**script_kwargs) wooey_script._script_cl_creation = True wooey_script.save() version_kwargs.update({'script_iteration': 1}) else: # we're updating it wooey_script = Script.objects.get(**script_kwargs) if not wooey_script.script_description and d['description']: wooey_script.script_description = d['description'] wooey_script.save() # check if we have the version in our script version current_versions = ScriptVersion.objects.filter(script=wooey_script, script_version=version_string) if current_versions.count() == 0: next_iteration = 1 # disable older versions ScriptVersion.objects.filter(script=wooey_script, script_version=version_string).update(default_version=False) else: # get the largest iteration and add 1 to it next_iteration = sorted([i.script_iteration for i in current_versions])[-1]+1 version_kwargs.update({'script_iteration': next_iteration}) version_kwargs.update({'script': wooey_script}) script_version = ScriptVersion(**version_kwargs) script_version._script_cl_creation = True script_version.save() else: # we are being created/updated from the admin if not script_version.script.script_description: script_version.script.script_description = d['description'] if not script_version.script.script_name: script_version.script.script_name = d['name'] past_versions = ScriptVersion.objects.filter(script=script_version.script, script_version=version_string).exclude(pk=script_version.pk) script_version.script_iteration = past_versions.count()+1 past_versions.update(default_version=False) script_version.default_version = True script_version.script.save() script_version.save() # make our parameters for param_group_info in d['inputs']: param_group, created = ScriptParameterGroup.objects.get_or_create(group_name=param_group_info.get('group'), script_version=script_version) for param in param_group_info.get('nodes'): # TODO: fix 'file' to be global in argparse is_out = True if param.get('upload', None) is False and param.get('type') == 'file' else not param.get('upload', False) script_param, created = ScriptParameter.objects.get_or_create(script_version=script_version, short_param=param['param'], script_param=param['name'], is_output=is_out, required=param.get('required', False), form_field=param['model'], default=param.get('default'), input_type=param.get('type'), choices=json.dumps(param.get('choices')), choice_limit=json.dumps(param.get('choice_limit', 1)), param_help=param.get('help'), is_checked=param.get('checked', False), parameter_group=param_group) return {'valid': True, 'errors': None, 'script': script_version}
def test_script_version(self): script_path = os.path.join(self.script_dir, 'choices.py') parser = Parser(script_path=script_path) description = parser.get_script_description() self.assertEqual(description['version'], '2' if six.PY2 else '3')