def _write_file_via_serial( self, source_fp: BinaryIO, target_path: str, file_size: int, callback: Callable[[int, int], None], ) -> None: out, err = self._execute( dedent(""" try: __thonny_path = '{path}' __thonny_written = 0 __thonny_fp = open(__thonny_path, 'wb') except Exception as e: print(str(e)) """).format(path=target_path), capture_output=True, ) if "readonly" in (out + err).replace("-", "").lower(): raise ReadOnlyFilesystemError() elif out + err: raise RuntimeError( "Could not open file %s for writing, output:\n%s" % (target_path, out + err)) # Define function to allow shorter write commands hex_mode = self._should_hexlify(target_path) if hex_mode: self._execute_without_output( dedent(""" from binascii import unhexlify as __thonny_unhex def __W(x): global __thonny_written __thonny_written += __thonny_fp.write(__thonny_unhex(x)) __thonny_fp.flush() if hasattr(__thonny_helper.os, "sync"): __thonny_helper.os.sync() """)) elif self._connected_to_microbit(): # doesn't have neither BytesIO.flush, nor os.sync self._execute_without_output( dedent(""" def __W(x): global __thonny_written __thonny_written += __thonny_fp.write(x) """)) else: self._execute_without_output( dedent(""" def __W(x): global __thonny_written __thonny_written += __thonny_fp.write(x) __thonny_fp.flush() if hasattr(__thonny_helper.os, "sync"): __thonny_helper.os.sync() """)) bytes_sent = 0 block_size = 512 while True: callback(bytes_sent, file_size) block = source_fp.read(block_size) if block: if hex_mode: script = "__W(%r)" % binascii.hexlify(block) else: script = "__W(%r)" % block out, err = self._execute(script, capture_output=True) if out or err: self._show_error( "\nCould not write next block after having written %d bytes to %s" % (bytes_sent, target_path)) if bytes_sent > 0: self._show_error( "Make sure your device's filesystem has enough free space. " + "(When overwriting a file, the old content may occupy space " "until the end of the operation.)\n") raise ManagementError(script, out, err) bytes_sent += len(block) if len(block) < block_size: break bytes_received = self._evaluate("__thonny_written") if bytes_received != bytes_sent: raise UserError("Expected %d written bytes but wrote %d" % (bytes_sent, bytes_received)) # clean up self._execute_without_output( dedent(""" try: del __W del __thonny_written del __thonny_path __thonny_fp.close() del __thonny_fp del __thonny_result del __thonny_unhex except: pass """)) return bytes_sent
def _write_file_via_serial(self, content_blocks, target_path, notifier=None): result = self._evaluate( dedent( """ try: __thonny_path = '{path}' __thonny_written = 0 __thonny_fp = open(__thonny_path, 'wb') __thonny_result = "OK" except Exception as e: __thonny_result = str(e) __thonny_helper.print_mgmt_value(__thonny_result) del __thonny_result """ ).format(path=target_path), ) if "readonly" in result.replace("-", "").lower(): raise ReadOnlyFilesystemError() elif result != "OK": raise RuntimeError("Problem opening file for writing: " + result) # Define function to allow shorter write commands hex_mode = self._should_hexlify(target_path) if hex_mode: self._execute_without_output( dedent( """ from binascii import unhexlify as __thonny_unhex def __W(x): global __thonny_written __thonny_written += __thonny_fp.write(__thonny_unhex(x)) __thonny_fp.flush() """ ) ) else: self._execute_without_output( dedent( """ def __W(x): global __thonny_written __thonny_written += __thonny_fp.write(x) """ ) ) bytes_sent = 0 for block in content_blocks: if hex_mode: script = "__W(%r)" % binascii.hexlify(block) else: script = "__W(%r)" % block self._execute_without_output(script) bytes_sent += len(block) if notifier is not None: notifier(bytes_sent) bytes_received = self._evaluate("__thonny_written") if bytes_received != bytes_sent: raise UserError("Expected %d written bytes but wrote %d" % (bytes_sent, bytes_received)) # clean up self._execute_without_output( dedent( """ try: del __W del __thonny_written del __thonny_path __thonny_fp.close() del __thonny_fp del __thonny_result del __thonny_unhex except: pass """ ) ) return bytes_sent