diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 94663b5c..499f5729 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,7 @@ jobs: outputs: output1: ${{ steps.step1.outputs.test }} steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Update Build Number @@ -30,12 +30,12 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Python - uses: actions/setup-python@v4.3.0 + uses: actions/setup-python@v5 with: python-version: 3.9 cache: 'pip' @@ -56,7 +56,7 @@ jobs: if: matrix.os == 'ubuntu-latest' - name: Upload Wheel - uses: actions/upload-artifact@v3.1.0 + uses: actions/upload-artifact@v4 with: name: pros-cli-wheel-${{needs.update_build_number.outputs.output1}} path: dist/* @@ -89,7 +89,7 @@ jobs: mv intercept-c++ pros - name: Upload Artifact - uses: actions/upload-artifact@v3.1.0 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.os }}-${{needs.update_build_number.outputs.output1}} - path: dist/* + path: dist/pros/* diff --git a/.gitignore b/.gitignore index 6fac33e7..0a5d8db3 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,6 @@ out/ *.zip *_pros_capture.png -venv/ - +*venv/ +.DS_Store *.pyc diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..da89c9c2 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include pros/autocomplete/* diff --git a/pip_version b/pip_version index e5b8a844..7d280e2c 100644 --- a/pip_version +++ b/pip_version @@ -1 +1 @@ -3.5.4 \ No newline at end of file +3.5.5 diff --git a/pros/cli/common.py b/pros/cli/common.py index 6c12fa06..ecdd2f20 100644 --- a/pros/cli/common.py +++ b/pros/cli/common.py @@ -268,7 +268,7 @@ def resolve_v5_port(port: Optional[str], type: str, quiet: bool = False) -> Tupl return None, False else: port = ports[0].device - is_joystick = type == 'user' and 'Controller' in ports[0].description + is_joystick = type == 'user' and ('Controller' in ports[0].description or ports[0].pid == 0x503) logger(__name__).info('Automatically selected {}'.format(port)) return port, is_joystick diff --git a/pros/cli/conductor.py b/pros/cli/conductor.py index 38d43235..78a03aa4 100644 --- a/pros/cli/conductor.py +++ b/pros/cli/conductor.py @@ -237,7 +237,7 @@ def new_project(ctx: click.Context, path: str, target: str, version: str, ui.echo('New PROS Project was created:', output_machine=False) ctx.invoke(info_project, project=project) - if compile_after or build_cache: + if (compile_after or build_cache) and not no_default_libs: with ui.Notification(): ui.echo('Building project...') exit_code = project.compile([], scan_build=build_cache) diff --git a/pros/cli/upload.py b/pros/cli/upload.py index 8c234ed8..95399b60 100644 --- a/pros/cli/upload.py +++ b/pros/cli/upload.py @@ -76,6 +76,8 @@ def upload(path: Optional[str], project: Optional[c.Project], port: str, **kwarg kwargs['slot'] = 1 if 'icon' in options and kwargs.get('icon','pros') == 'pros': kwargs.pop('icon') + if 'description' in options and kwargs.get('description','Made with PROS') == 'Made with PROS': + kwargs.pop('description') if 'after' in options and kwargs.get('after','screen') is None: kwargs.pop('after') diff --git a/pros/conductor/project/ProjectReport.py b/pros/conductor/project/ProjectReport.py index 75d2ff3a..38388334 100644 --- a/pros/conductor/project/ProjectReport.py +++ b/pros/conductor/project/ProjectReport.py @@ -17,8 +17,10 @@ def __str__(self): f' ({self.project["name"]})' if self.project["name"] else '' s += '\n' rows = [t.values() for t in self.project["templates"]] - headers = [h.capitalize() for h in self.project["templates"][0].keys()] + + headers = [h.capitalize() for h in self.project["templates"][0].keys()]if self.project["templates"] else [] s += tabulate.tabulate(rows, headers=headers) + return s def __getstate__(self): diff --git a/pros/conductor/project/__init__.py b/pros/conductor/project/__init__.py index 575f9c4d..1c981126 100644 --- a/pros/conductor/project/__init__.py +++ b/pros/conductor/project/__init__.py @@ -166,8 +166,6 @@ def new_user_filter(new_file: str) -> bool: def remove_template(self, template: Template, remove_user: bool = False, remove_empty_directories: bool = True): if not self.template_is_installed(template): raise ValueError(f'{template.identifier} is not installed on this project.') - if template.name == 'kernel': - raise ValueError(f'Cannot remove the kernel template. Maybe create a new project?') real_template = LocalTemplate(orig=template, location=self.location) transaction = Transaction(self.location, set(self.all_files)) diff --git a/pros/config/config.py b/pros/config/config.py index 984b668a..c7250620 100644 --- a/pros/config/config.py +++ b/pros/config/config.py @@ -25,7 +25,7 @@ def __init__(self, file, error_on_decode=False): if file: # If the file already exists, update this new config with the values in the file if os.path.isfile(file): - with open(file, 'r') as f: + with open(file, 'r', encoding ='utf-8') as f: try: result = jsonpickle.decode(f.read()) if isinstance(result, dict): diff --git a/pros/serial/devices/vex/v5_device.py b/pros/serial/devices/vex/v5_device.py index 2720c0c1..6ec6913d 100644 --- a/pros/serial/devices/vex/v5_device.py +++ b/pros/serial/devices/vex/v5_device.py @@ -585,7 +585,14 @@ def write_file(self, file: typing.BinaryIO, remote_file: str, file_len: int = -1 if compress and self.status['system_version'] in Spec('>=1.0.5'): logger(__name__).info('Closing gzip file') file.close() - self.ft_complete(options=run_after) + # The time to write the file to flash isn't exactly linear with the file size, + # but it's okay even if we slightly underestimate as long as we get a response back + # on one of the 3 tries of ft_complete. + # The point is to set our timeout window so we aren't waiting too long for a response + # that will never happen if, for example, the brain turned off. + ft_timeout = max(file_len/200000, 1.0) + logger(__name__).debug(f'Setting file transfer timeout as {ft_timeout:.2f} seconds') + self.ft_complete(options=run_after, timeout=ft_timeout) @with_download_channel def capture_screen(self) -> Tuple[List[List[int]], int, int]: @@ -688,12 +695,12 @@ def ft_initialize(self, file_name: str, **kwargs) -> Dict[str, Any]: return rx @retries - def ft_complete(self, options: FTCompleteOptions = FTCompleteOptions.DONT_RUN): + def ft_complete(self, options: FTCompleteOptions = FTCompleteOptions.DONT_RUN, timeout: float = 1.0): logger(__name__).debug('Sending ext 0x12 command') if isinstance(options, bool): options = self.FTCompleteOptions.RUN_IMMEDIATELY if options else self.FTCompleteOptions.DONT_RUN tx_payload = struct.pack("