Skip to content

Commit b30e223

Browse files
curiouswalaclaude
andcommitted
fix: clean up errors, exit codes, and ls directory display
- Remove leftover debug print("here we are") from reset command - reset --safe/--bootloader now exits 1 when unsupported on MicroPython - run with a missing local file now exits 1 instead of silently succeeding - Add AmypGroup (custom Click Group) to catch RuntimeError and DirectoryExistsError at the top level — users see a clean "Error: ..." message instead of a raw Python traceback - Fix rm error handling: conditions used != 1 instead of != -1, and ENOTEMPTY was checked as errno 13 (wrong) instead of 39; now parses the errno number from the OSError message for accurate messages - ls -l and ls -r -l now show "<dir>" for directories instead of a meaningless block-size byte count from MicroPython's os.stat - Add import re to files.py (needed by the new errno parsing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent bac4f5a commit b30e223

2 files changed

Lines changed: 39 additions & 15 deletions

File tree

ampy/cli.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@
4242
_board = None
4343

4444

45+
class AmypGroup(click.Group):
46+
"""Custom Click group that converts RuntimeError / DirectoryExistsError into
47+
clean error messages instead of raw Python tracebacks."""
48+
49+
def invoke(self, ctx):
50+
try:
51+
return super().invoke(ctx)
52+
except files.DirectoryExistsError as e:
53+
click.echo("Error: {}".format(e), err=True)
54+
raise SystemExit(1)
55+
except RuntimeError as e:
56+
click.echo("Error: {}".format(e), err=True)
57+
raise SystemExit(1)
58+
59+
4560
def windows_full_port_name(portname):
4661
# Helper function to generate proper Windows COM port paths. Apparently
4762
# Windows requires COM ports above 9 to have a special path, where ports below
@@ -55,7 +70,7 @@ def windows_full_port_name(portname):
5570
return "\\\\.\\{0}".format(portname)
5671

5772

58-
@click.group()
73+
@click.group(cls=AmypGroup)
5974
@click.option(
6075
"--port",
6176
"-p",
@@ -357,6 +372,7 @@ def run(local_file, no_output):
357372
click.echo(
358373
"Failed to find or read input file: {0}".format(local_file), err=True
359374
)
375+
raise SystemExit(1)
360376

361377

362378
@cli.command()
@@ -417,10 +433,9 @@ def reset():
417433
"""
418434
)
419435
r = _board.eval("on_next_reset({})".format(repr(mode)))
420-
print("here we are", repr(r))
421436
if r:
422-
click.echo(r, err=True)
423-
return
437+
click.echo(r.decode("utf-8"), err=True)
438+
raise SystemExit(1)
424439

425440
try:
426441
_board.exec_raw_no_follow("reset()")

ampy/files.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
# SOFTWARE.
2222
import ast
23+
import re
2324
import textwrap
2425
import binascii
2526

@@ -153,8 +154,11 @@ def listdir(directory):
153154
command += """
154155
r = []
155156
for f in listdir('{0}'):
156-
size = os.stat(f)[6]
157-
r.append('{{0}} - {{1}} bytes'.format(f, size))
157+
st = os.stat(f)
158+
if st[0] & 0x4000:
159+
r.append('{{0}} - <dir>'.format(f))
160+
else:
161+
r.append('{{0}} - {{1}} bytes'.format(f, st[6]))
158162
print(r)
159163
""".format(
160164
directory
@@ -243,15 +247,20 @@ def rm(self, filename):
243247
out = self._pyboard.exec_(textwrap.dedent(command))
244248
except PyboardError as ex:
245249
message = ex.args[2].decode("utf-8")
246-
# Check if this is an OSError #2, i.e. file/directory doesn't exist
247-
# and rethrow it as something more descriptive.
248-
if message.find("OSError") != -1 and message.find("2") != 1:
249-
raise RuntimeError("No such file/directory: {0}".format(filename))
250-
# Check for OSError #13, the directory isn't empty.
251-
if message.find("OSError") != -1 and message.find("13") != 1:
252-
raise RuntimeError("Directory is not empty: {0}".format(filename))
253-
else:
254-
raise ex
250+
if "OSError" in message:
251+
# Extract errno number — MicroPython formats as either
252+
# "OSError: 2" or "OSError: [Errno 2] ENOENT"
253+
errno_match = re.search(r"OSError:.*?(\d+)", message)
254+
errno_val = int(errno_match.group(1)) if errno_match else None
255+
if errno_val == 2: # ENOENT
256+
raise RuntimeError("No such file/directory: {0}".format(filename))
257+
elif errno_val == 21: # EISDIR
258+
raise RuntimeError(
259+
"Is a directory (use rmdir to remove): {0}".format(filename)
260+
)
261+
elif errno_val == 39: # ENOTEMPTY
262+
raise RuntimeError("Directory is not empty: {0}".format(filename))
263+
raise ex
255264
self._pyboard.exit_raw_repl()
256265

257266
def rmdir(self, directory, missing_okay=False):

0 commit comments

Comments
 (0)