From b5ee8a464385ca0ae029690abb636e719c29e037 Mon Sep 17 00:00:00 2001 From: Mayank Patibandla <34776435+mayankpatibandla@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:46:26 -0400 Subject: [PATCH] Formatter --- pros/cli/build.py | 12 +- pros/cli/common.py | 37 ++-- pros/cli/conductor.py | 262 +++++++++++++++++++++-------- pros/cli/main.py | 52 +++--- pros/cli/upload.py | 6 +- pros/cli/v5_utils.py | 22 ++- pros/conductor/conductor.py | 111 ++++++------ pros/conductor/project/__init__.py | 17 +- 8 files changed, 340 insertions(+), 179 deletions(-) diff --git a/pros/cli/build.py b/pros/cli/build.py index 845bd0d2..fcf512d9 100644 --- a/pros/cli/build.py +++ b/pros/cli/build.py @@ -27,12 +27,12 @@ def make(project: c.Project, build_args): analytics.send("make") exit_code = project.compile(build_args) if exit_code != 0: - if sys.platform == 'win32': + if sys.platform == "win32": kernel32 = ctypes.windll.kernel32 kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) - logger(__name__).error(f'Failed to make project: Exit Code {exit_code}', extra={'sentry': False}) - raise click.ClickException('Failed to build') + logger(__name__).error(f"Failed to make project: Exit Code {exit_code}", extra={"sentry": False}) + raise click.ClickException("Failed to build") return exit_code @@ -82,10 +82,10 @@ def build_compile_commands( build_args, cdb_file=compile_commands, suppress_output=suppress_output, sandbox=sandbox ) if exit_code != 0: - if sys.platform == 'win32': + if sys.platform == "win32": kernel32 = ctypes.windll.kernel32 kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) - logger(__name__).error(f'Failed to make project: Exit Code {exit_code}', extra={'sentry': False}) - raise click.ClickException('Failed to build') + logger(__name__).error(f"Failed to make project: Exit Code {exit_code}", extra={"sentry": False}) + raise click.ClickException("Failed to build") return exit_code diff --git a/pros/cli/common.py b/pros/cli/common.py index f66c0a7d..c3dc8a9e 100644 --- a/pros/cli/common.py +++ b/pros/cli/common.py @@ -166,8 +166,18 @@ def callback(ctx: click.Context, param: click.Parameter, value: bool): add_tag("no-sentry", value) if value: pros.common.sentry.disable_prompt() - decorator = click.option('--no-sentry', expose_value=False, is_flag=True, default=True, is_eager=True, - help="Disable sentry reporting prompt.", callback=callback, cls=PROSOption, hidden=True)(f) + + decorator = click.option( + "--no-sentry", + expose_value=False, + is_flag=True, + default=True, + is_eager=True, + help="Disable sentry reporting prompt.", + callback=callback, + cls=PROSOption, + hidden=True, + )(f) decorator.__name__ = f.__name__ return decorator @@ -251,9 +261,11 @@ def callback(ctx: click.Context, param: click.Parameter, value: str): if allow_none: return None elif required: - raise click.UsageError(f'{os.path.abspath(value or ".")} is not inside a PROS project. ' - f'Execute this command from within a PROS project or specify it ' - f'with --project project/path') + raise click.UsageError( + f'{os.path.abspath(value or ".")} is not inside a PROS project. ' + f"Execute this command from within a PROS project or specify it " + f"with --project project/path" + ) else: return None @@ -324,12 +336,15 @@ def resolve_v5_port(port: Optional[str], type: str, quiet: bool = False) -> Tupl return None, False if len(ports) > 1: if not quiet: - brain_id = click.prompt('Multiple {} Brains were found. Please choose one to upload the program: [{}]' - .format('v5', ' | '.join([p.product.split(' ')[-1] for p in ports])), - default=ports[0].product.split(' ')[-1], - show_default=False, - type=click.Choice([p.description.split(' ')[-1] for p in ports])) - port = [p.device for p in ports if p.description.split(' ')[-1] == brain_id][0] + brain_id = click.prompt( + "Multiple {} Brains were found. Please choose one to upload the program: [{}]".format( + "v5", " | ".join([p.product.split(" ")[-1] for p in ports]) + ), + default=ports[0].product.split(" ")[-1], + show_default=False, + type=click.Choice([p.description.split(" ")[-1] for p in ports]), + ) + port = [p.device for p in ports if p.description.split(" ")[-1] == brain_id][0] assert port in [p.device for p in ports] else: diff --git a/pros/cli/conductor.py b/pros/cli/conductor.py index a9786c70..8a06487e 100644 --- a/pros/cli/conductor.py +++ b/pros/cli/conductor.py @@ -67,9 +67,9 @@ def fetch(query: c.BaseTemplate): logger(__name__).debug(f"Template file found: {template_file}") else: if template_file: - logger(__name__).debug(f'Template file exists but is not a valid template: {template_file}') + logger(__name__).debug(f"Template file exists but is not a valid template: {template_file}") else: - logger(__name__).error(f'Template not found: {query.name}') + logger(__name__).error(f"Template not found: {query.name}") return -1 template = c.Conductor().resolve_template(query, allow_offline=False) logger(__name__).debug(f"Template from resolved query: {template}") @@ -84,22 +84,51 @@ def fetch(query: c.BaseTemplate): c.Conductor().fetch_template(depot, template, **query.metadata) -@conductor.command(context_settings={'ignore_unknown_options': True}) -@click.option('--upgrade/--no-upgrade', 'upgrade_ok', default=True, help='Allow upgrading templates in a project') - -@click.option('--install/--no-install', 'install_ok', default=True, help='Allow installing templates in a project') -@click.option('--download/--no-download', 'download_ok', default=True, - help='Allow downloading templates or only allow local templates') -@click.option('--upgrade-user-files/--no-upgrade-user-files', 'force_user', default=False, - help='Replace all user files in a template') -@click.option('--force', 'force_system', default=False, is_flag=True, - help="Force all system files to be inserted into the project") -@click.option('--force-apply', 'force_apply', default=False, is_flag=True, - help="Force apply the template, disregarding if the template is already installed.") -@click.option('--remove-empty-dirs/--no-remove-empty-dirs', 'remove_empty_directories', is_flag=True, default=True, - help='Remove empty directories when removing files') -@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None, - help='Create a project using the PROS 4 kernel') +@conductor.command(context_settings={"ignore_unknown_options": True}) +@click.option("--upgrade/--no-upgrade", "upgrade_ok", default=True, help="Allow upgrading templates in a project") +@click.option("--install/--no-install", "install_ok", default=True, help="Allow installing templates in a project") +@click.option( + "--download/--no-download", + "download_ok", + default=True, + help="Allow downloading templates or only allow local templates", +) +@click.option( + "--upgrade-user-files/--no-upgrade-user-files", + "force_user", + default=False, + help="Replace all user files in a template", +) +@click.option( + "--force", + "force_system", + default=False, + is_flag=True, + help="Force all system files to be inserted into the project", +) +@click.option( + "--force-apply", + "force_apply", + default=False, + is_flag=True, + help="Force apply the template, disregarding if the template is already installed.", +) +@click.option( + "--remove-empty-dirs/--no-remove-empty-dirs", + "remove_empty_directories", + is_flag=True, + default=True, + help="Remove empty directories when removing files", +) +@click.option( + "--early-access/--no-early-access", + "--early/--no-early", + "-ea/-nea", + "early_access", + "--beta/--no-beta", + default=None, + help="Create a project using the PROS 4 kernel", +) @project_option() @template_query(required=True) @default_options @@ -153,19 +182,41 @@ def install(ctx: click.Context, **kwargs): return ctx.invoke(apply, install_ok=True, **kwargs) -@conductor.command(context_settings={'ignore_unknown_options': True}, aliases=['u']) -@click.option('--install/--no-install', 'install_ok', default=False) -@click.option('--download/--no-download', 'download_ok', default=True) -@click.option('--force-user', 'force_user', default=False, is_flag=True, - help='Replace all user files in a template') -@click.option('--force-system', '-f', 'force_system', default=False, is_flag=True, - help="Force all system files to be inserted into the project") -@click.option('--force-apply', 'force_apply', default=False, is_flag=True, - help="Force apply the template, disregarding if the template is already installed.") -@click.option('--remove-empty-dirs/--no-remove-empty-dirs', 'remove_empty_directories', is_flag=True, default=True, - help='Remove empty directories when removing files') -@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None, - help='Create a project using the PROS 4 kernel') +@conductor.command(context_settings={"ignore_unknown_options": True}, aliases=["u"]) +@click.option("--install/--no-install", "install_ok", default=False) +@click.option("--download/--no-download", "download_ok", default=True) +@click.option("--force-user", "force_user", default=False, is_flag=True, help="Replace all user files in a template") +@click.option( + "--force-system", + "-f", + "force_system", + default=False, + is_flag=True, + help="Force all system files to be inserted into the project", +) +@click.option( + "--force-apply", + "force_apply", + default=False, + is_flag=True, + help="Force apply the template, disregarding if the template is already installed.", +) +@click.option( + "--remove-empty-dirs/--no-remove-empty-dirs", + "remove_empty_directories", + is_flag=True, + default=True, + help="Remove empty directories when removing files", +) +@click.option( + "--early-access/--no-early-access", + "--early/--no-early", + "-ea/-nea", + "early_access", + "--beta/--no-beta", + default=None, + help="Create a project using the PROS 4 kernel", +) @project_option() @template_query(required=False) @default_options @@ -222,24 +273,52 @@ def uninstall_template( project.compile(["clean"]) -@conductor.command('new-project', aliases=['new', 'create-project']) -@click.argument('path', type=click.Path()) -@click.argument('target', default=c.Conductor().default_target, type=click.Choice(['v5', 'cortex'])) -@click.argument('version', default='latest') -@click.option('--force-user', 'force_user', default=False, is_flag=True, - help='Replace all user files in a template') -@click.option('--force-system', '-f', 'force_system', default=False, is_flag=True, - help="Force all system files to be inserted into the project") -@click.option('--force-refresh', is_flag=True, default=False, show_default=True, - help='Force update all remote depots, ignoring automatic update checks') -@click.option('--no-default-libs', 'no_default_libs', default=False, is_flag=True, - help='Do not install any default libraries after creating the project.') -@click.option('--compile-after', is_flag=True, default=True, show_default=True, - help='Compile the project after creation') -@click.option('--build-cache', is_flag=True, default=None, show_default=False, - help='Build compile commands cache after creation. Overrides --compile-after if both are specified.') -@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None, - help='Create a project using the PROS 4 kernel') +@conductor.command("new-project", aliases=["new", "create-project"]) +@click.argument("path", type=click.Path()) +@click.argument("target", default=c.Conductor().default_target, type=click.Choice(["v5", "cortex"])) +@click.argument("version", default="latest") +@click.option("--force-user", "force_user", default=False, is_flag=True, help="Replace all user files in a template") +@click.option( + "--force-system", + "-f", + "force_system", + default=False, + is_flag=True, + help="Force all system files to be inserted into the project", +) +@click.option( + "--force-refresh", + is_flag=True, + default=False, + show_default=True, + help="Force update all remote depots, ignoring automatic update checks", +) +@click.option( + "--no-default-libs", + "no_default_libs", + default=False, + is_flag=True, + help="Do not install any default libraries after creating the project.", +) +@click.option( + "--compile-after", is_flag=True, default=True, show_default=True, help="Compile the project after creation" +) +@click.option( + "--build-cache", + is_flag=True, + default=None, + show_default=False, + help="Build compile commands cache after creation. Overrides --compile-after if both are specified.", +) +@click.option( + "--early-access/--no-early-access", + "--early/--no-early", + "-ea/-nea", + "early_access", + "--beta/--no-beta", + default=None, + help="Create a project using the PROS 4 kernel", +) @click.pass_context @default_options def new_project( @@ -301,25 +380,56 @@ def new_project( ctx.exit(-1) -@conductor.command('query-templates', - aliases=['search-templates', 'ls-templates', 'lstemplates', 'querytemplates', 'searchtemplates', 'q'], - context_settings={'ignore_unknown_options': True}) -@click.option('--allow-offline/--no-offline', 'allow_offline', default=True, show_default=True, - help='(Dis)allow offline templates in the listing') -@click.option('--allow-online/--no-online', 'allow_online', default=True, show_default=True, - help='(Dis)allow online templates in the listing') -@click.option('--force-refresh', is_flag=True, default=False, show_default=True, - help='Force update all remote depots, ignoring automatic update checks') -@click.option('--limit', type=int, default=15, - help='The maximum number of displayed results for each library') -@click.option('--early-access/--no-early-access', '--early/--no-early', '-ea/-nea', 'early_access', '--beta/--no-beta', default=None, - help='View a list of early access templates') +@conductor.command( + "query-templates", + aliases=["search-templates", "ls-templates", "lstemplates", "querytemplates", "searchtemplates", "q"], + context_settings={"ignore_unknown_options": True}, +) +@click.option( + "--allow-offline/--no-offline", + "allow_offline", + default=True, + show_default=True, + help="(Dis)allow offline templates in the listing", +) +@click.option( + "--allow-online/--no-online", + "allow_online", + default=True, + show_default=True, + help="(Dis)allow online templates in the listing", +) +@click.option( + "--force-refresh", + is_flag=True, + default=False, + show_default=True, + help="Force update all remote depots, ignoring automatic update checks", +) +@click.option("--limit", type=int, default=15, help="The maximum number of displayed results for each library") +@click.option( + "--early-access/--no-early-access", + "--early/--no-early", + "-ea/-nea", + "early_access", + "--beta/--no-beta", + default=None, + help="View a list of early access templates", +) @template_query(required=False) @project_option(required=False) @click.pass_context @default_options -def query_templates(ctx, project: Optional[c.Project], query: c.BaseTemplate, allow_offline: bool, allow_online: bool, force_refresh: bool, - limit: int, early_access: bool): +def query_templates( + ctx, + project: Optional[c.Project], + query: c.BaseTemplate, + allow_offline: bool, + allow_online: bool, + force_refresh: bool, + limit: int, + early_access: bool, +): """ Query local and remote templates based on a spec @@ -330,8 +440,13 @@ def query_templates(ctx, project: Optional[c.Project], query: c.BaseTemplate, al limit = 15 if early_access is None and project is not None: early_access = project.use_early_access - templates = c.Conductor().resolve_templates(query, allow_offline=allow_offline, allow_online=allow_online, - force_refresh=force_refresh, early_access=early_access) + templates = c.Conductor().resolve_templates( + query, + allow_offline=allow_offline, + allow_online=allow_online, + force_refresh=force_refresh, + early_access=early_access, + ) render_templates = {} for template in templates: key = (template.identifier, template.origin) @@ -430,10 +545,11 @@ def query_depots(url: bool): """ _conductor = c.Conductor() ui.echo(f"Available Depots{' (Add --url for the url)' if not url else ''}:\n") - ui.echo('\n'.join(_conductor.query_depots(url))+"\n") + ui.echo("\n".join(_conductor.query_depots(url)) + "\n") + -@conductor.command('reset') -@click.option('--force', is_flag=True, default=False, help='Force reset') +@conductor.command("reset") +@click.option("--force", is_flag=True, default=False, help="Force reset") @default_options def reset(force: bool): """ @@ -443,12 +559,14 @@ def reset(force: bool): """ if not force: - if not ui.confirm("This will remove all depots and templates. You will be unable to create a new PROS project if you do not have internet connection. Are you sure you want to continue?"): + if not ui.confirm( + "This will remove all depots and templates. You will be unable to create a new PROS project if you do not have internet connection. Are you sure you want to continue?" + ): ui.echo("Aborting") return - + # Delete conductor.pros - file = os.path.join(click.get_app_dir('PROS'), 'conductor.pros') + file = os.path.join(click.get_app_dir("PROS"), "conductor.pros") if os.path.exists(file): os.remove(file) diff --git a/pros/cli/main.py b/pros/cli/main.py index 9d83fd9c..70a982dd 100644 --- a/pros/cli/main.py +++ b/pros/cli/main.py @@ -18,24 +18,12 @@ import pros.common.sentry import pros.common.ui as ui import pros.common.ui.log +import pros.conductor as c from pros.cli.click_classes import * from pros.cli.common import default_options, root_commands from pros.common.utils import get_version, logger from pros.ga.analytics import analytics -import jsonpickle -import pros.cli.build -import pros.cli.conductor -import pros.cli.conductor_utils -import pros.cli.terminal -import pros.cli.upload -import pros.cli.v5_utils -import pros.cli.misc_commands -import pros.cli.interactive -import pros.cli.user_script -import pros.conductor as c - - if sys.platform == "win32": kernel32 = ctypes.windll.kernel32 kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) @@ -113,9 +101,10 @@ def use_analytics(ctx: click.Context, param, value): ctx.exit(0) ctx.ensure_object(dict) analytics.set_use(touse) - ui.echo(f'Analytics usage set to: {analytics.useAnalytics}') + ui.echo(f"Analytics usage set to: {analytics.useAnalytics}") ctx.exit(0) - + + def use_early_access(ctx: click.Context, param, value): if value is None: return @@ -126,22 +115,39 @@ def use_early_access(ctx: click.Context, param, value): elif value.startswith("f") or value in ["0", "no", "n"]: conductor.use_early_access = False else: - ui.echo('Invalid argument provided for \'--use-early-access\'. Try \'--use-early-access=False\' or \'--use-early-access=True\'') + ui.echo( + "Invalid argument provided for '--use-early-access'. Try '--use-early-access=False' or '--use-early-access=True'" + ) ctx.exit(0) conductor.save() - ui.echo(f'Early access set to: {conductor.use_early_access}') + ui.echo(f"Early access set to: {conductor.use_early_access}") ctx.exit(0) @click.command("pros", cls=PROSCommandCollection, sources=root_commands) @click.pass_context @default_options -@click.option('--version', help='Displays version and exits.', is_flag=True, expose_value=False, is_eager=True, - callback=version) -@click.option('--use-analytics', help='Set analytics usage (True/False).', type=str, expose_value=False, - is_eager=True, default=None, callback=use_analytics) -@click.option('--use-early-access', type=str, expose_value=False, is_eager=True, default=None, - help='Create projects with PROS 4 kernel by default', callback=use_early_access) +@click.option( + "--version", help="Displays version and exits.", is_flag=True, expose_value=False, is_eager=True, callback=version +) +@click.option( + "--use-analytics", + help="Set analytics usage (True/False).", + type=str, + expose_value=False, + is_eager=True, + default=None, + callback=use_analytics, +) +@click.option( + "--use-early-access", + type=str, + expose_value=False, + is_eager=True, + default=None, + help="Create projects with PROS 4 kernel by default", + callback=use_early_access, +) def cli(ctx): pros.common.sentry.register() ctx.call_on_close(after_command) diff --git a/pros/cli/upload.py b/pros/cli/upload.py index 972acc76..9712bf8f 100644 --- a/pros/cli/upload.py +++ b/pros/cli/upload.py @@ -261,9 +261,9 @@ def __str__(self): ports = find_v5_ports("system") result.append(PortReport("VEX EDR V5 System Ports", ports, "v5/system")) - ports = find_v5_ports('User') - result.append(PortReport('VEX EDR V5 User Ports', ports, 'v5/user')) - if target == 'cortex' or target is None: + ports = find_v5_ports("User") + result.append(PortReport("VEX EDR V5 User Ports", ports, "v5/user")) + if target == "cortex" or target is None: ports = find_cortex_ports() result.append(PortReport("VEX EDR Cortex Microcontroller Ports", ports, "cortex")) diff --git a/pros/cli/v5_utils.py b/pros/cli/v5_utils.py index 47c3b0e0..f22cbe74 100644 --- a/pros/cli/v5_utils.py +++ b/pros/cli/v5_utils.py @@ -313,10 +313,13 @@ def capture(file_name: str, port: str, force: bool = False): print(f"Saved screen capture to {file_name}") -@v5.command('set-variable', aliases=['sv', 'set', 'set_variable'], short_help='Set a kernel variable on a connected V5 device') -@click.argument('variable', type=click.Choice(['teamnumber', 'robotname']), required=True) -@click.argument('value', required=True, type=click.STRING, nargs=1) -@click.argument('port', type=str, default=None, required=False) + +@v5.command( + "set-variable", aliases=["sv", "set", "set_variable"], short_help="Set a kernel variable on a connected V5 device" +) +@click.argument("variable", type=click.Choice(["teamnumber", "robotname"]), required=True) +@click.argument("value", required=True, type=click.STRING, nargs=1) +@click.argument("port", type=str, default=None, required=False) @default_options def set_variable(variable, value, port): import pros.serial.devices.vex as vex @@ -330,9 +333,14 @@ def set_variable(variable, value, port): actual_value = device.kv_write(variable, value).decode() print(f"Value of '{variable}' set to : {actual_value}") -@v5.command('read-variable', aliases=['rv', 'get', 'read_variable'], short_help='Read a kernel variable from a connected V5 device') -@click.argument('variable', type=click.Choice(['teamnumber', 'robotname']), required=True) -@click.argument('port', type=str, default=None, required=False) + +@v5.command( + "read-variable", + aliases=["rv", "get", "read_variable"], + short_help="Read a kernel variable from a connected V5 device", +) +@click.argument("variable", type=click.Choice(["teamnumber", "robotname"]), required=True) +@click.argument("port", type=str, default=None, required=False) @default_options def read_variable(variable, port): import pros.serial.devices.vex as vex diff --git a/pros/conductor/conductor.py b/pros/conductor/conductor.py index cad827a1..151e29f8 100644 --- a/pros/conductor/conductor.py +++ b/pros/conductor/conductor.py @@ -1,11 +1,11 @@ import errno import os.path +import re import shutil +import sys from enum import Enum from pathlib import Path -import sys from typing import * -import re import click from semantic_version import Spec, Version @@ -31,40 +31,35 @@ class ReleaseChannel(Enum): Beta = 'beta' """ + def is_pathname_valid(pathname: str) -> bool: - ''' + """ A more detailed check for path validity than regex. https://stackoverflow.com/a/34102855/11177720 - ''' + """ try: if not isinstance(pathname, str) or not pathname: return False - + _, pathname = os.path.splitdrive(pathname) - - root_dirname = os.environ.get('HOMEDRIVE', 'C:') \ - if sys.platform == 'win32' else os.path.sep + + root_dirname = os.environ.get("HOMEDRIVE", "C:") if sys.platform == "win32" else os.path.sep assert os.path.isdir(root_dirname) - + root_dirname = root_dirname.rstrip(os.path.sep) + os.path.sep for pathname_part in pathname.split(os.path.sep): try: os.lstat(root_dirname + pathname_part) except OSError as exc: - if hasattr(exc, 'winerror'): - if exc.winerror == 123: # ERROR_INVALID_NAME, python doesn't have this constant + if hasattr(exc, "winerror"): + if exc.winerror == 123: # ERROR_INVALID_NAME, python doesn't have this constant return False elif exc.errno in {errno.ENAMETOOLONG, errno.ERANGE}: return False - + # Check for emojis # https://stackoverflow.com/a/62898106/11177720 - ranges = [ - (ord(u'\U0001F300'), ord(u"\U0001FAF6")), # 127744, 129782 - (126980, 127569), - (169, 174), - (8205, 12953) - ] + ranges = [(ord("\U0001F300"), ord("\U0001FAF6")), (126980, 127569), (169, 174), (8205, 12953)] # 127744, 129782 for a_char in pathname: char_code = ord(a_char) for range_min, range_max in ranges: @@ -75,6 +70,7 @@ def is_pathname_valid(pathname: str) -> bool: else: return True + class Conductor(Config): """ Provides entrances for all conductor-related tasks (fetching, applying, creating new projects) @@ -195,9 +191,9 @@ def resolve_templates( **kwargs, ) -> List[BaseTemplate]: results = list() if not unique else set() - kernel_version = kwargs.get('kernel_version', None) - if kwargs.get('early_access', None) is not None: - use_early_access = kwargs.get('early_access', False) + kernel_version = kwargs.get("kernel_version", None) + if kwargs.get("early_access", None) is not None: + use_early_access = kwargs.get("early_access", False) else: use_early_access = self.use_early_access if isinstance(identifier, str): @@ -208,7 +204,11 @@ def resolve_templates( offline_results = list() if use_early_access: - offline_results.extend(filter(lambda t: t.satisfies(query, kernel_version=kernel_version), self.early_access_local_templates)) + offline_results.extend( + filter( + lambda t: t.satisfies(query, kernel_version=kernel_version), self.early_access_local_templates + ) + ) offline_results.extend( filter(lambda t: t.satisfies(query, kernel_version=kernel_version), self.local_templates) @@ -315,18 +315,19 @@ def apply_template(self, project: Project, identifier: Union[str, BaseTemplate], f"Do you still want to downgrade?" ) if not confirm: - raise dont_send( - InvalidTemplateException(f'Not downgrading')) - elif not project.use_early_access and template.version[0] == '3' and not self.warn_early_access: - confirm = ui.confirm(f'PROS 4 is now in early access. ' - f'Please use the --early-access flag if you would like to use it.\n' - f'Do you want to use PROS 4 instead?') + raise dont_send(InvalidTemplateException(f"Not downgrading")) + elif not project.use_early_access and template.version[0] == "3" and not self.warn_early_access: + confirm = ui.confirm( + f"PROS 4 is now in early access. " + f"Please use the --early-access flag if you would like to use it.\n" + f"Do you want to use PROS 4 instead?" + ) self.warn_early_access = True - if confirm: # use pros 4 + if confirm: # use pros 4 project.use_early_access = True project.save() - kwargs['version'] = '>=0' - kwargs['early_access'] = True + kwargs["version"] = ">=0" + kwargs["early_access"] = True # Recall the function with early access enabled return self.apply_template(project, identifier, **kwargs) @@ -383,39 +384,40 @@ def remove_template( ) def new_project(self, path: str, no_default_libs: bool = False, **kwargs) -> Project: - if kwargs.get('early_access', None) is not None: - use_early_access = kwargs.get('early_access', False) + if kwargs.get("early_access", None) is not None: + use_early_access = kwargs.get("early_access", False) else: use_early_access = self.use_early_access kwargs["early_access"] = use_early_access - if kwargs["version_source"]: # If true, then the user has not specified a version + if kwargs["version_source"]: # If true, then the user has not specified a version if not use_early_access and self.warn_early_access: - ui.echo(f"PROS 4 is now in early access. " - f"If you would like to use it, use the --early-access flag.") + ui.echo(f"PROS 4 is now in early access. " f"If you would like to use it, use the --early-access flag.") elif not use_early_access and not self.warn_early_access: - confirm = ui.confirm(f'PROS 4 is now in early access. ' - f'Please use the --early-access flag if you would like to use it.\n' - f'Do you want to use PROS 4 instead?') + confirm = ui.confirm( + f"PROS 4 is now in early access. " + f"Please use the --early-access flag if you would like to use it.\n" + f"Do you want to use PROS 4 instead?" + ) self.warn_early_access = True if confirm: use_early_access = True - kwargs['early_access'] = True + kwargs["early_access"] = True elif use_early_access: - ui.echo(f'Early access is enabled. Using PROS 4.') + ui.echo(f"Early access is enabled. Using PROS 4.") elif use_early_access: - ui.echo(f'Early access is enabled.') + ui.echo(f"Early access is enabled.") if not is_pathname_valid(str(Path(path).absolute())): - raise dont_send(ValueError('Project path contains invalid characters.')) - - if Path(path).exists() and Path(path).samefile(os.path.expanduser('~')): - raise dont_send(ValueError('Will not create a project in user home directory')) - + raise dont_send(ValueError("Project path contains invalid characters.")) + + if Path(path).exists() and Path(path).samefile(os.path.expanduser("~")): + raise dont_send(ValueError("Will not create a project in user home directory")) + proj = Project(path=path, create=True, early_access=use_early_access) - if 'target' in kwargs: - proj.target = kwargs['target'] - if 'project_name' in kwargs and kwargs['project_name'] and not kwargs['project_name'].isspace(): - proj.project_name = kwargs['project_name'] + if "target" in kwargs: + proj.target = kwargs["target"] + if "project_name" in kwargs and kwargs["project_name"] and not kwargs["project_name"].isspace(): + proj.project_name = kwargs["project_name"] else: proj.project_name = os.path.basename(os.path.normpath(os.path.abspath(path))) if "version" in kwargs: @@ -425,7 +427,12 @@ def new_project(self, path: str, no_default_libs: bool = False, **kwargs) -> Pro proj.save() if not no_default_libs: - libraries = self.early_access_libraries if proj.use_early_access and (kwargs.get("version", ">").startswith("4") or kwargs.get("version", ">").startswith(">")) else self.default_libraries + libraries = ( + self.early_access_libraries + if proj.use_early_access + and (kwargs.get("version", ">").startswith("4") or kwargs.get("version", ">").startswith(">")) + else self.default_libraries + ) for library in libraries[proj.target]: try: # remove kernel version so that latest template satisfying query is correctly selected diff --git a/pros/conductor/project/__init__.py b/pros/conductor/project/__init__.py index 603ee6ee..773e1c60 100644 --- a/pros/conductor/project/__init__.py +++ b/pros/conductor/project/__init__.py @@ -17,7 +17,14 @@ class Project(Config): - def __init__(self, path: str = '.', create: bool = False, raise_on_error: bool = True, defaults: dict = None, early_access: bool = False): + def __init__( + self, + path: str = ".", + create: bool = False, + raise_on_error: bool = True, + defaults: dict = None, + early_access: bool = False, + ): """ Instantiates a PROS project configuration :param path: A path to the project, may be the actual project.pros file, any child directory of the project, @@ -35,10 +42,10 @@ def __init__(self, path: str = '.', create: bool = False, raise_on_error: bool = if defaults is None: defaults = {} - self.target: str = defaults.get('target', 'cortex').lower() # VEX Hardware target (V5/Cortex) - self.templates: Dict[str, Template] = defaults.get('templates', {}) - self.upload_options: Dict = defaults.get('upload_options', {}) - self.project_name: str = defaults.get('project_name', None) + self.target: str = defaults.get("target", "cortex").lower() # VEX Hardware target (V5/Cortex) + self.templates: Dict[str, Template] = defaults.get("templates", {}) + self.upload_options: Dict = defaults.get("upload_options", {}) + self.project_name: str = defaults.get("project_name", None) self.use_early_access = early_access super(Project, self).__init__(file, error_on_decode=raise_on_error) if "kernel" in self.__dict__: