mpytool 2.3.5__tar.gz → 2.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mpytool-2.3.5 → mpytool-2.3.6}/PKG-INFO +2 -1
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/_version.py +3 -3
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/mpy_cross.py +23 -2
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool.egg-info/PKG-INFO +2 -1
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool.egg-info/SOURCES.txt +1 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool.egg-info/requires.txt +1 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/pyproject.toml +1 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_cli.py +8 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_cmd_cp.py +7 -6
- mpytool-2.3.6/tests/test_helpers.py +24 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_integration.py +8 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/.github/workflows/integration.yml +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/.github/workflows/publish.yml +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/.github/workflows/tests.yml +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/.gitignore +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/LICENSE +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/README.md +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/README_API.md +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/README_bench.md +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/README_mpremote.md +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/completions/_mpytool +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/completions/mpytool.bash +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/__init__.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/cmd_cp.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/conn.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/conn_serial.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/conn_socket.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/logger.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/mount.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/mpy.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/mpy_comm.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/mpytool.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/speedtest.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/terminal.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/terminal_unix.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/terminal_win.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool/utils.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool.egg-info/dependency_links.txt +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool.egg-info/entry_points.txt +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/mpytool.egg-info/top_level.txt +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/setup.cfg +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/__init__.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_errors.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_mount.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_mpy.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_mpytool.py +0 -0
- {mpytool-2.3.5 → mpytool-2.3.6}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mpytool
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.6
|
|
4
4
|
Summary: MPY tool - manage files on devices running MicroPython
|
|
5
5
|
Author-email: Pavel Revak <pavelrevak@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -10,6 +10,7 @@ Requires-Python: >=3.10
|
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Requires-Dist: pyserial>=3.0
|
|
13
|
+
Requires-Dist: mpy-cross
|
|
13
14
|
Dynamic: license-file
|
|
14
15
|
|
|
15
16
|
# mpytool
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '2.3.
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 3,
|
|
31
|
+
__version__ = version = '2.3.6'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 3, 6)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g9d48ac194'
|
|
@@ -5,6 +5,7 @@ import os as _os
|
|
|
5
5
|
import re as _re
|
|
6
6
|
import shutil as _shutil
|
|
7
7
|
import subprocess as _subprocess
|
|
8
|
+
import sys as _sys
|
|
8
9
|
|
|
9
10
|
from mpytool.logger import SimpleColorLogger as _SimpleColorLogger
|
|
10
11
|
|
|
@@ -19,6 +20,21 @@ _MPY_ARCH_NAMES = (
|
|
|
19
20
|
BOOT_FILES = frozenset(('boot.py', 'main.py'))
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
def _find_mpy_cross():
|
|
24
|
+
"""Find mpy-cross binary: first in same dir as Python, then in PATH"""
|
|
25
|
+
# Look next to current Python interpreter (same venv)
|
|
26
|
+
bin_dir = _os.path.dirname(_sys.executable)
|
|
27
|
+
local = _os.path.join(bin_dir, 'mpy-cross')
|
|
28
|
+
if _os.path.isfile(local) and _os.access(local, _os.X_OK):
|
|
29
|
+
return local
|
|
30
|
+
# Windows: mpy-cross.exe
|
|
31
|
+
local_exe = local + '.exe'
|
|
32
|
+
if _os.path.isfile(local_exe) and _os.access(local_exe, _os.X_OK):
|
|
33
|
+
return local_exe
|
|
34
|
+
# Fallback to PATH
|
|
35
|
+
return _shutil.which('mpy-cross')
|
|
36
|
+
|
|
37
|
+
|
|
22
38
|
class MpyCross:
|
|
23
39
|
"""Mpy-cross compiler wrapper with caching
|
|
24
40
|
|
|
@@ -29,6 +45,7 @@ class MpyCross:
|
|
|
29
45
|
def __init__(self, log=None):
|
|
30
46
|
self._log = log if log is not None else _SimpleColorLogger()
|
|
31
47
|
self.active = False
|
|
48
|
+
self._bin = None # path to mpy-cross binary
|
|
32
49
|
self._ver = None # (major, sub) device mpy version
|
|
33
50
|
self._arch = None # architecture name for cache key
|
|
34
51
|
self._args = [] # extra mpy-cross args (-b, -march)
|
|
@@ -53,7 +70,7 @@ class MpyCross:
|
|
|
53
70
|
Sets self.active = True on success, False on failure.
|
|
54
71
|
"""
|
|
55
72
|
self.active = False
|
|
56
|
-
mpy_cross_bin =
|
|
73
|
+
mpy_cross_bin = _find_mpy_cross()
|
|
57
74
|
if not mpy_cross_bin:
|
|
58
75
|
self._log.warning(
|
|
59
76
|
'mpy-cross not found in PATH (pip install mpy-cross),'
|
|
@@ -99,6 +116,7 @@ class MpyCross:
|
|
|
99
116
|
self._log.debug(
|
|
100
117
|
'device v%s mpy v%d.%d%s, mpy-cross %s',
|
|
101
118
|
dev_version, dev_ver, dev_sub, arch_str, cross_str)
|
|
119
|
+
self._bin = mpy_cross_bin
|
|
102
120
|
self.active = True
|
|
103
121
|
|
|
104
122
|
def compile(self, src_path):
|
|
@@ -106,7 +124,10 @@ class MpyCross:
|
|
|
106
124
|
|
|
107
125
|
Skips boot.py, main.py, and non-.py files.
|
|
108
126
|
Uses cache if fresh (mtime check).
|
|
127
|
+
Returns None if not active (init() not called or failed).
|
|
109
128
|
"""
|
|
129
|
+
if not self.active:
|
|
130
|
+
return None
|
|
110
131
|
basename = _os.path.basename(src_path)
|
|
111
132
|
if basename in BOOT_FILES:
|
|
112
133
|
self._log.debug('mpy: skip %s (boot file)', basename)
|
|
@@ -126,7 +147,7 @@ class MpyCross:
|
|
|
126
147
|
return cache_path
|
|
127
148
|
# Compile
|
|
128
149
|
_os.makedirs(cache_dir, exist_ok=True)
|
|
129
|
-
cmd = [
|
|
150
|
+
cmd = [self._bin] + self._args + ['-o', cache_path, src_path]
|
|
130
151
|
self._log.info('$ %s', ' '.join(cmd))
|
|
131
152
|
result = _subprocess.run(
|
|
132
153
|
cmd, capture_output=True, text=True, timeout=30)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mpytool
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.6
|
|
4
4
|
Summary: MPY tool - manage files on devices running MicroPython
|
|
5
5
|
Author-email: Pavel Revak <pavelrevak@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -10,6 +10,7 @@ Requires-Python: >=3.10
|
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Requires-Dist: pyserial>=3.0
|
|
13
|
+
Requires-Dist: mpy-cross
|
|
13
14
|
Dynamic: license-file
|
|
14
15
|
|
|
15
16
|
# mpytool
|
|
@@ -51,6 +51,14 @@ def requires_device_rw(cls):
|
|
|
51
51
|
return cls
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
def setUpModule():
|
|
55
|
+
"""Reset device before running CLI tests"""
|
|
56
|
+
if not PORT_RO:
|
|
57
|
+
return # No device, tests will be skipped
|
|
58
|
+
from tests.test_helpers import reset_device
|
|
59
|
+
reset_device(PORT_RO)
|
|
60
|
+
|
|
61
|
+
|
|
54
62
|
# =============================================================================
|
|
55
63
|
# Tests without device (always run)
|
|
56
64
|
# =============================================================================
|
|
@@ -738,6 +738,7 @@ class TestMpyCompilation(unittest.TestCase):
|
|
|
738
738
|
def _setup_compiler(self, arch=None):
|
|
739
739
|
"""Setup compiler with active state and fake version"""
|
|
740
740
|
self.compiler.active = True
|
|
741
|
+
self.compiler._bin = 'mpy-cross'
|
|
741
742
|
self.compiler._ver = (6, 3)
|
|
742
743
|
self.compiler._arch = arch
|
|
743
744
|
self.compiler._args = []
|
|
@@ -915,9 +916,9 @@ class TestMpyCompilation(unittest.TestCase):
|
|
|
915
916
|
self.assertEqual(call_args[0][0], compiled_data)
|
|
916
917
|
self.assertEqual(call_args[0][1], '/script.mpy')
|
|
917
918
|
|
|
918
|
-
@patch('mpytool.mpy_cross.
|
|
919
|
+
@patch('mpytool.mpy_cross._find_mpy_cross', return_value='/usr/bin/mpy-cross')
|
|
919
920
|
@patch('mpytool.mpy_cross._subprocess.run')
|
|
920
|
-
def test_init_version_match(self, mock_run,
|
|
921
|
+
def test_init_version_match(self, mock_run, mock_find):
|
|
921
922
|
"""init should succeed when versions match"""
|
|
922
923
|
mock_run.return_value = Mock(
|
|
923
924
|
returncode=0,
|
|
@@ -930,9 +931,9 @@ class TestMpyCompilation(unittest.TestCase):
|
|
|
930
931
|
self.assertEqual(self.compiler._ver, (6, 3))
|
|
931
932
|
self.assertIn('-march=armv6m', self.compiler._args)
|
|
932
933
|
|
|
933
|
-
@patch('mpytool.mpy_cross.
|
|
934
|
+
@patch('mpytool.mpy_cross._find_mpy_cross', return_value='/usr/bin/mpy-cross')
|
|
934
935
|
@patch('mpytool.mpy_cross._subprocess.run')
|
|
935
|
-
def test_init_version_mismatch_uses_b_flag(self, mock_run,
|
|
936
|
+
def test_init_version_mismatch_uses_b_flag(self, mock_run, mock_find):
|
|
936
937
|
"""init should use -b flag on version mismatch"""
|
|
937
938
|
mock_run.return_value = Mock(
|
|
938
939
|
returncode=0,
|
|
@@ -947,8 +948,8 @@ class TestMpyCompilation(unittest.TestCase):
|
|
|
947
948
|
self.assertIn('6.1', self.compiler._args)
|
|
948
949
|
self.assertIn('-march=xtensawin', self.compiler._args)
|
|
949
950
|
|
|
950
|
-
@patch('mpytool.mpy_cross.
|
|
951
|
-
def test_init_not_found(self,
|
|
951
|
+
@patch('mpytool.mpy_cross._find_mpy_cross', return_value=None)
|
|
952
|
+
def test_init_not_found(self, mock_find):
|
|
952
953
|
"""init should deactivate when mpy-cross not in PATH"""
|
|
953
954
|
self.compiler._log = Mock()
|
|
954
955
|
self.compiler.init({'mpy_ver': 6, 'mpy_sub': 3, 'version': '1.24.0'})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Shared test helpers for integration and CLI tests"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def reset_device(port):
|
|
5
|
+
"""Reset device before tests and wait for it to be ready
|
|
6
|
+
|
|
7
|
+
Tries hardware reset first (USB-UART), falls back to soft reset (CDC).
|
|
8
|
+
Actively waits for REPL to be ready (no fixed sleep).
|
|
9
|
+
"""
|
|
10
|
+
from mpytool import ConnSerial, Mpy
|
|
11
|
+
from mpytool.conn import ConnError
|
|
12
|
+
|
|
13
|
+
conn = ConnSerial(port=port, baudrate=115200)
|
|
14
|
+
mpy = Mpy(conn)
|
|
15
|
+
try:
|
|
16
|
+
# Try hardware reset first (USB-UART only)
|
|
17
|
+
conn.hard_reset()
|
|
18
|
+
except ConnError:
|
|
19
|
+
# CDC devices don't support hardware reset, use soft reset
|
|
20
|
+
mpy.soft_reset()
|
|
21
|
+
# Wait for device to boot and REPL to be ready
|
|
22
|
+
mpy.comm._repl_mode = None # Force re-detection
|
|
23
|
+
mpy.comm.stop_current_operation()
|
|
24
|
+
conn.close()
|
|
@@ -53,6 +53,14 @@ def requires_device_rw(cls):
|
|
|
53
53
|
requires_device_wipe = requires_device_rw
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
def setUpModule():
|
|
57
|
+
"""Reset device before running integration tests"""
|
|
58
|
+
if not PORT_RO:
|
|
59
|
+
return # No device, tests will be skipped
|
|
60
|
+
from tests.test_helpers import reset_device
|
|
61
|
+
reset_device(PORT_RO)
|
|
62
|
+
|
|
63
|
+
|
|
56
64
|
@requires_device
|
|
57
65
|
class TestDeviceConnection(unittest.TestCase):
|
|
58
66
|
"""Test basic device connection"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|