Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change --text from argument to option #28

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,42 +143,70 @@ Labelle includes the Carlito font, licensed under the

## Modes

### Print text
### Overview

```labelle MyText```
For a comprehensive list of options, run

Multilines will be generated on whitespace
```bash
labelle --help
```

### Preview

```labelle MyLine MySecondLine # Will print two Lines```
To save tape, you can preview the label without printing it

If you want whitespaces just enclose in " "
```bash
labelle --output=console --text Hi
```

```labelle "prints a single line"```
![Hi](doc/hi.png)

### Print QRCodes and Barcodes
### Text

```labelle --help```
If your text includes whitespace or any other characters like `<` or `$` that are
interpreted by your shell, then the text must be quoted.

```bash
labelle --text 'Price: $3.50'
```

![Price: $3.50](doc/3-50.png)

Multiple text arguments will stack on top of each other as separate lines

```bash
labelle --text "first line" --text "second line"
```

![first line second line](doc/two-lines.png)

### Print Codes and Text

Just add a text after your qr or barcode text

```labelle -qr "QR Content" "Cleartext printed"```
```bash
labelle --qr "QR Content" --text "Cleartext printed"
```

![QR Content Cleartext printed](doc/qr-with-text.png)

### Picture printing

Any picture with JPEG standard may be printed. Beware it will be downsized to tape.
Any commonly-supported raster image may be printed.

```labelle -p mypic.jpg ""```
```bash
labelle --picture labelle.png
```

Take care of the trailing "" - you may enter text here which gets printed in
front of the image
![labelle.png](doc/labelle-label.png)

## GUI

### Run Labelle GUI

```labelle-gui```
```bash
labelle-gui
```

### GUI App Features

Expand Down
Binary file added doc/3-50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/hi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/labelle-label.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/qr-with-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/two-lines.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ commands =
labelle --version
labelle --help
python -c "import labelle.gui.gui; print('GUI import succeeded')"
labelle --output console "single line"
labelle --output console-inverted "inverted"
labelle --output console multiple lines
labelle --output console --text "single line"
labelle --output console-inverted --text "inverted"
labelle --output console --text multiple --text lines
labelle --output console --barcode "Barcode" --barcode-type code128
labelle --output console --barcode-with-text "Barcode" --barcode-type code128 Caption
labelle --output console --qr QR
labelle --output console --qr QR Caption
labelle --output console --barcode-with-text "Barcode" --barcode-type code128 --text "Caption"
labelle --output console --qr "QR"
labelle --output console --qr "QR" --text "Caption"
labelle --output console --picture ./labelle.png

[testenv:{clean,build}]
Expand Down
33 changes: 31 additions & 2 deletions src/labelle/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@
# this notice are preserved.
# === END LICENSE STATEMENT ===
import logging
import shlex
import sys
from pathlib import Path
from typing import List, NoReturn, Optional

import typer
from click.exceptions import ClickException
from click.exceptions import UsageError as ClickUsageError
from rich.console import Console
from rich.table import Table
from typer.rich_utils import rich_format_error
from typing_extensions import Annotated

from labelle import __version__
Expand Down Expand Up @@ -130,7 +135,7 @@ def default(
] = None,
text: Annotated[
Optional[List[str]],
typer.Argument(
typer.Option(
help="Text, each parameter gives a new line",
rich_help_panel="Elements",
),
Expand Down Expand Up @@ -554,9 +559,33 @@ def default(
output_bitmap(bitmap, output)


def add_hint_about_text_option(e: ClickException) -> None:
"""Insert a suggestion to use the --text flag when a command is not found.

In dymoprint the --text option was implicit. If labelle is invoked without
--text, it presents as a ClickUsageError with the message "No such command..."
We append to this error message a hint to use the --text flag.
"""
if isinstance(e, ClickUsageError):
# Enhance the error message for dymoprint users who are
# not used to the --text flag being mandatory.
if e.message.startswith("No such command '") and e.message.endswith("'."):
command = e.message[17:-2]
e.message += f""" Did you mean {shlex.join(['--text', command])} ?"""


def main() -> None:
configure_logging()
app()
try:
app(standalone_mode=False)
except ClickException as e:
# Use standalone mode to avoid typer's default error handling here:
# <https://github.com/tiangolo/typer/blob/773927208fbf03d30d50fc39fe2a1a18b7bd93cb/typer/core.py#L207-L216>
# This allows us to add the following hint:
add_hint_about_text_option(e)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't test it, so I might be wrong here, but I think this function should return True in case it found "No such command" and updated the message.
In case of True, it should do the following two lines:

rich_format_error(e)
sys.exit(e.exit_code)

Otherwise, it should raise.
This way we'll get proper error/exception handling by typer, except for this specific case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function only runs if there is an exception. In that case, it doesn't handle the exception, it simply mutates the message when necessary. Those two lines run in any case in order to handle the exception, so I don't see how returning a boolean would help. Does that make sense?

The goal is basically to handle the standalone_mode=False branches from the code linked in the comment. Based on my own tests I think it's working well, but it'd be great if you could try if you can break something.


rich_format_error(e)
sys.exit(e.exit_code)


if __name__ == "__main__":
Expand Down
25 changes: 25 additions & 0 deletions src/labelle/cli/tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import sys

import pytest
from typer.testing import CliRunner

from labelle.cli.cli import main

runner = CliRunner()


def test_text_hint(monkeypatch):
# This is NOT the recommended way of testing Typer applications.
# We are doing it this way because we added additional error handling
# in main() which we need to test.
with monkeypatch.context() as m:
m.setattr(sys, "argv", ["labelle", "hello world"])
with runner.isolation(input=None, env=None, color=False) as outstreams:
with pytest.raises(SystemExit):
main()
sys.stdout.flush()
stdout = outstreams[0].getvalue()
assert (
b"""No such command 'hello world'. Did you mean --text 'hello world' ?"""
in stdout
)