def execute_command(): source = paths.resource('tracksim.global.sh') with open(source, 'r+') as f: contents = f.read() path = paths.project('bin', 'tracksim') contents = contents.replace('###TRACKSIM_PATH###', path) path = '/usr/local/bin/tracksim' with open(path, 'w+') as f: f.write(contents) os.chmod( path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH ) register_global_var() system.log(""" [SUCCESS]: The tracksim command has been registered for global use. You can now call tracksim globally from a terminal. If you have trouble calling tracksim, make sure you have exported /usr/local/bin in your .bash_profile PATH. """)
def fetch_command(): """ :return: """ cmd = None if len(sys.argv) > 1: cmd = sys.argv[1].lower() if cmd in ['-h', '-help', '--help', '--h']: return 'help' if cmd is None or cmd.startswith('-'): system.log(""" [ERROR]: tracksim requires a command argument that defines the operation to be carried out. The expected structure is: $ tracksim [COMMAND] [ARGUMENTS] [--OPTIONS] For a list of available commands run: $ tracksim help """) system.end(1) return cmd
def list_modules(): for key in dir(ME): item = getattr(ME, key) if hasattr(item, 'DESCRIPTION'): print('') system.log('[{}]:\n {}'.format( key.strip('_'), cli.reformat(getattr(item, 'DESCRIPTION')) .replace('\n', '\n ') ))
def test_logging(self): """ """ system.log('This is a test') system.log([ '1', ['2', '3', ['4', '5', '6'] ] ])
def error_and_exit(label, key): system.log(""" [ERROR]: No {label} was specified in your tracksim settings. Use the configure command to fix this: $ tracksim configure {key} "[{LABEL}]" or specify the {label} in your deploy command. For details run: $ tracksim deploy help """.format(label=label, key=key, LABEL=label.upper())) sys.exit(1)
def show_help(): """ Prints the basic command help to the console """ system.log('The following commands are available:') list_modules() msg = """ For more information on the various commands, use the help flag on the specific command: tracksim [COMMAND] --help """ system.log(msg, whitespace_top=1)
def echo_key(configs: dict, key: str): """ :param configs: :param key: :return: """ if key not in configs: system.log('[MISSING]: No "{}" key was found'.format(key)) return system.log('[VALUE]: "{}" = {}'.format(key, configs[key]))
def find_group_files(path: str) -> typing.List[str]: """ Finds all group configuration JSON files stored in the specified path directory :param path: Path to the directory where the group files search should take place """ paths = [] # Prioritize group files named "group.json" over other files in the path items = ['group.json'] for item in os.listdir(path): if item == 'group.json': continue items.append(item) for item in items: item_path = os.path.join(path, item) if not os.path.exists(item_path): continue if not os.path.isfile(item_path) or not item.endswith('.json'): continue try: with open(item_path, 'r+') as f: data = json.load(f) except json_decoder.JSONDecodeError as err: system.log([ '[ERROR]: Failed to decode json file', [ 'PATH: {}'.format(path), 'INFO: {}'.format(err.msg), [ 'LINE: {}'.format(err.lineno), 'CHAR: {}'.format(err.colno) ] ] ]) return system.end(1) if 'trials' in data: paths.append(item_path) if not paths: system.log('ERROR: No group trial found in path: "{}"'.format(path)) system.end(2) return paths
def execute_command(): """ Runs the deploy command """ parser = ArgumentParser() parser.description = cli.reformat(DESCRIPTION) parser.add_argument( 'deploy', type=str, help='The deploy command to execute' ) parser.add_argument( 'root_path', type=str, help=cli.reformat(""" The folder in the S3 bucket where your files will be uploaded """) ) parser.add_argument( '-p', '--profile', dest='profile', type=str, default=None, help=cli.reformat(""" The name of the AWS credentials profile to use for access to the AWS S3 bucket resources """) ) parser.add_argument( '-b', '--bucket', dest='bucket', type=str, default=None, help=cli.reformat(""" The name of the S3 bucket where the files will be uploaded """) ) args = vars(parser.parse_args()) configs = system.load_configs() upload_in_folder( get_aws_settings(configs, **args), paths.results('report') ) system.log('[COMPLETE]: Trials have been deployed')
def echo_all(configs: dict): """ :param configs: :return: """ keys = list(configs.keys()) keys.sort() out = ['Current Configuration:'] for k in keys: out.append(' * {key}: {value}'.format(key=k, value=configs[k])) system.log('\n'.join(out))
def execute_command(): path = '/usr/local/bin/tracksim' if not os.path.exists(path): system.log(cli.reformat(""" [INFO]: The tracksim command was not registered. Operation aborted. """)) return os.remove(path) system.log(""" [SUCCESS]: The tracksim command is no longer registered for global use. """)
def print_results(urls: typing.List[str]): """ :param urls: :return: """ msg = """ ------------------------------------------ Simulation Complete. Results Available At: """ system.log(msg, whitespace=1) for r in urls: system.log(' * {}'.format(r))
def remove_key(configs: dict, key: str): """ Removes the specified key from the tracksim configs if the key exists :param configs: The tracksim configs object to modify :param key: The key in the tracksim configs object to remove """ if key in configs: del configs[key] system.save_configs(configs) system.log( '[REMOVED]: "{}" from configuration settings'.format(key) )
def list_trials(): system.log("===== TRIALS =====", whitespace_bottom=1) results_path = paths.results("trials.html") for uid, data_path in reader.listings("trial").items(): url = "file://{}?id={}".format(results_path, uid) system.log( """ --- {uid} --- {url} """.format( uid=uid, url=url ), whitespace_bottom=1, )
def run(**kwargs): """ :param kwargs: :return: """ cli_configs = kwargs.get('settings') if cli_configs is None: cli_configs = system.load_configs() path = get_path(kwargs.get('path'), cli_configs) if path is None: system.log('ERROR: Invalid or missing path argument') sys.exit(1) urls = [] if os.path.isfile(path): with open(path, 'r+') as f: data = json.load(f) urls.append(run_simulation( is_group=bool('trials' in data), cli_configs=cli_configs, settings_path=path, **kwargs )) else: group_paths = find_group_files(path) if not kwargs.get('run_all_groups'): group_paths = group_paths[0:1] for p in group_paths: urls.append(run_simulation( is_group=True, cli_configs=cli_configs, settings_path=p, **kwargs )) save_recent_path(kwargs.get('path'), cli_configs) print_results(urls)
def execute_command(): """ :return: """ parser = ArgumentParser() parser.description = cli.reformat(DESCRIPTION) parser.add_argument( 'generate_command', type=str, help='The generate command itself' ) parser.add_argument( 'trial_or_group', type=str, help='Path to a trial or group file where the data source is specified' ) parser.add_argument( 'output_filename', type=str, help='Name of the csv file to be created' ) args = parser.parse_args() cli_configs = system.load_configs() path = get_path(args.trial_or_group, cli_configs) if path is None: system.log('ERROR: Invalid or missing trial/group path') sys.exit(1) settings = configs.load(None, path) out_path = os.path.join(settings['directory'], args.output_filename) simulate.load_trackway_positions( settings, save_as=out_path )
def set_key(configs: dict, key: str, value: typing.List[str]): """ Removes the specified key from the tracksim configs if the key exists :param configs: The tracksim configs object to modify :param key: The key in the tracksim configs object to remove :param value: """ if key.startswith('path.'): for index in range(len(value)): value[index] = paths.clean(value[index]) if len(value) == 1: value = value[0] configs[key] = value system.save_configs(configs) system.log('[SET]: "{}" to "{}"'.format(key, value))
def run( settings: typing.Union[str, dict], **kwargs ) -> dict: """ Executes a grouped collection of simulation trials and returns the compiled results for the individual trials, as well as results calculated for the group of trials :param settings: Settings for running the group of trials. Each trial configuration will inherit values from these settings. :param kwargs: Optional setting overrides to be included in the group configuration """ settings = configs.load('group', settings, **kwargs) trials = [] system.log('[{}]: STARTING'.format(settings['id'])) for source in fetch_trial_list(settings): if isinstance(source, str): original = source source = os.path.abspath(os.path.join(settings['path'], source)) if not os.path.exists(source): source = '{}.json'.format(source) if not os.path.exists(source): system.log( """ [ERROR]: Unable to locate simulation trial file "{}" """.format(original) ) raise FileNotFoundError('No such file {}'.format(source)) trial_settings = configs.load('trial', source, inherits=settings) simulate_trial.run(trial_settings) trials.append(dict( settings=trial_settings, index=len(trials) + 1, id=trial_settings['id'], )) system.log('[{}]: ANALYZING'.format(settings['id'])) url = analyze.create(settings, trials) system.log('[{}]: COMPLETE'.format(settings['id'])) return url
def execute_command(): """ :return: """ system.log(""" ============== REMOVE RESULTS ============== This command will remove all analysis, group and trial reports stored located in the directory: {} """.format(paths.results()), whitespace_bottom=1) do_it = query.confirm( 'Are you sure you want to continue', default=False ) if not do_it: system.log('[ABORTED]: No files were deleted') return system.end(0) path = paths.results('reports') if os.path.exists(path): try: shutil.rmtree(path) except Exception: try: shutil.rmtree(path) except Exception: pass system.log(""" [SUCCESS]: All results have been removed """, whitespace_top=1)
def run( path: str, source_directory: str, directory_name: str, force: bool, **kwargs ): """ :param path: :param source_directory: :param directory_name: :param force: :return: """ target_path = os.path.join(os.path.abspath(path), directory_name) if os.path.exists(target_path): if not force: system.log(""" [ABORTED EXPORT] A file or directory already exists at the specified path: {path} If you would like to replace the existing data at this path location either delete the existing data first, or run this command with the force flag. """.format(path=target_path)) system.end(1) system.log('[REMOVING]: Existing directory {}'.format(target_path)) try: shutil.rmtree(target_path) except OSError: try: # Give it a second shutil.rmtree(target_path) except OSError: system.log(""" [ABORTED EXPORT] The existing directory could not be removed. Unable to continue. """) system.end(1) omit_html = kwargs.get('omit_html', False) omit_data = kwargs.get('omit_data', False) def list_ignores(src, names): """ Creates a list of file names that should not be copied to the destination during the copytree operation. :param src: Source directory where the files originate :param names: A list of file names in the source directory to filter :return: A list of file names in the source directory that should NOT be copied to the destination path """ ignored_names = [] for name in names: if omit_html and not name.endswith('.json'): ignored_names.append(name) if omit_data and name.endswith('.json'): ignored_names.append(name) return ignored_names shutil.copytree(source_directory, target_path, ignore=list_ignores) result = create_index_file(source_directory, target_path) system.log(""" [EXPORT COMPLETE] The export process was successful. All existing reports are now accessible through the index file: * {url} """.format(url=result['url']), whitespace=1)
def run( settings: typing.Union[str, dict], trackway_positions: trackway.TrackPosition = None, **kwargs ) -> dict: """ Runs and analyzes a simulation of the trackway under the conditions specified by the arguments and returns a dictionary of results for the trial :param settings: Either a dictionary containing the configuration values for the trial or an absolute path to a json format file that contains the configuration values for the trial :param trackway_positions: A TrackwayDefinition instance populated with phase and position values """ settings = configs.load('trial', settings, **kwargs) if 'steps_per_cycle' not in settings: settings['steps_per_cycle'] = 20 if 'moving_ambiguity' not in settings: # The coefficient of uncertainty while the foot is moving settings['moving_ambiguity'] = 0.1 if 'duty_cycle' not in settings: settings['duty_cycle'] = 0.6 system.log('[{}]: STARTING'.format(settings['id'])) activity_phases = load_activity_phases(settings) trackway_positions = load_trackway_positions(settings, trackway_positions) trackway_definition = trackway.TrackwayDefinition( trackway_positions, activity_phases ) trackway_definition.reorient_positions() foot_positions = limb.Property() time_steps = list(generate.time_steps_from_data( settings['steps_per_cycle'], trackway_definition )) for key in limb.KEYS: out = compute.positions_over_time( time_steps=time_steps, limb_positions=trackway_definition.limb_positions.get(key), activity_phase=trackway_definition.activity_phases.get(key), settings=settings ) foot_positions.set(key, out) prune.invalid_positions( settings, time_steps, foot_positions ) if len(time_steps) < 1: system.log( """ [{}]: INVALID RESULTS There are no simulated results to analyze. Either the simulation is not valid, or you have set a start and end time that is not within the range of valid values. Please check your settings file. """.format(settings['id'])) raise ValueError('Invalid Results') system.log('[{}]: ANALYZING'.format(settings['id'])) reorientation_needed = prune.unused_foot_prints( trackway_definition.limb_positions, foot_positions ) if reorientation_needed: # Reorient positions again now that the trackway has been pruned trackway_definition.reorient_positions( *foot_positions.left_pes, *foot_positions.right_pes, *foot_positions.left_manus, *foot_positions.right_manus ) url = analyze.create( track_definition=trackway_definition, settings=settings, time_steps=time_steps, foot_positions=foot_positions ) system.log('[{}]: COMPLETED'.format(settings['id'])) return url
def load_trackway_positions( settings: dict, existing: limb.Property = None, save_as: str = None ) -> limb.Property: """ Loads the trackway positions for the trial from the information provided in the settings object, unless an existing trackway positions object has been specified :param settings: Configuration for the simulation trial :param existing: Optionally the already loaded trackway positions, which will be cloned and returned if present :param save_as: An optional path where the loaded trackway positions shold be saved """ if existing: # Ignore if already specified return existing.clone() data = settings.get('data') if isinstance(data, str): # Load from a specified file if not data.startswith('/'): data = os.path.join(settings['path'], data) if not os.path.exists(data): system.log( """ [ERROR]: No CSV source data exists at the path: {} """.format(data) ) raise FileNotFoundError('No CSV source file found') return trackway.load_positions_file(data) # Generate from configuration settings track_offsets = limb.Property().assign(*data['offsets']) out = generate.trackway_positions( cycle_count=data['count'], step_size=data['step_size'], track_offsets=track_offsets, lateral_displacement=data['lateral_displacement'], positional_uncertainty=data.get('uncertainty') ) if not save_as and data.get('save'): save_as = data.get('save') if save_as: trackway.save_positions_file( trackway_positions=out, path=os.path.join(settings['directory'], save_as) ) return out
def load( configs_type: typing.Union[str, None], source: typing.Union[str, dict], inherits: dict = None, **kwargs ) -> dict: """ Loads a JSON configuration file from the specified source path if the source argument is a string. Otherwise, assumes the source is already a dictionary object with the configuration information. Then any specified keyword arguments are added to the configurations, replacing any keys that were already defined. :param configs_type: The enumerated type of the configurations to be loaded :param source: Either a string representing an absolute path to the configs JSON file to be loaded, or a dictionary object of configuration values :param inherits: An optional dictionary of values that should be inherited where they do not exist already in the source settings :return: The loaded configuration dictionary object augmented by any keyword arguments """ c = configs_type[0].lower() if configs_type else None if c == 't': configs_type = 'trial' elif c == 'g': configs_type = 'group' else: configs_type = None if isinstance(source, str): path = source try: with open(path, 'r+') as f: source = json.load(f) except FileNotFoundError: system.log([ '[ERROR]: No such configuration file', ['PATH: {}'.format(path)] ]) return system.end(1) except json_decoder.JSONDecodeError as err: system.log([ '[ERROR]: Failed to decode configs json file', [ 'PATH: {}'.format(path), 'INFO: {}'.format(err.msg), [ 'LINE: {}'.format(err.lineno), 'CHAR: {}'.format(err.colno) ] ] ]) return system.end(1) source['filename'] = os.path.abspath(path) source['path'] = os.path.dirname(source['filename']) source['directory'] = os.path.dirname(source['filename']) else: source = json.loads(json.dumps(source)) source['path'] = source.get('path', os.path.abspath(os.path.curdir)) source['directory'] = source.get( 'directory', os.path.abspath(os.path.curdir) ) if configs_type is None: configs_type = 'g' if 'trials' in source else 't' source['type'] = configs_type if inherits: for k, v in inherits.items(): if configs_type == 'trial' and k in ['trials']: continue if k not in source: source[k] = v for k, v in kwargs.items(): source[k] = v source['id'] = source['name'].replace(' ', '-') return source