Skip to content

Commit

Permalink
Allow the use of sequence names (#36)
Browse files Browse the repository at this point in the history
* This enables avoiding imports
* It is not a breaking change, the old way still works

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
qexat and pre-commit-ci[bot] authored Jul 31, 2023
1 parent 87dbd8d commit ea7fa05
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 33 deletions.
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ Even though the examples are mostly showcasing [SGR escape sequences](https://en

```py
from coquille import Coquille
from coquille.sequences import bold, fg_magenta, italic

print("Hello World!")

# By default, the coquille wraps the standard output
with Coquille.new(fg_magenta, italic) as coquille:
with Coquille.new("fg_magenta", "italic") as coquille:
print("Hello World, but in magenta and italic!")
coquille.apply(bold)
coquille.apply("bold")
print("Now, with a touch of bold :D")

print("Oh, we are back to normal now...")

```

![screenshot.png](https://raw.githubusercontent.com/qexat/Coquille/main/examples/coquille_context/screenshot.png)
Expand All @@ -42,14 +42,13 @@ Source code: [examples/coquille_context/](https://github.com/qexat/Coquille/blob

```py
from coquille import write
from coquille.sequences import bold, fg_blue, fg_magenta, italic

print("Hello World!")

write("Hello World, but in magenta and italic!", fg_magenta, italic)
write("Hello World, but in magenta and italic!", "fg_magenta", "italic")

with open("examples/write/output.txt", "w") as my_file:
write("A pretty Hello World in a file!", fg_blue, bold, file=my_file)
write("A pretty Hello World in a file!", "fg_blue", "bold", file=my_file)

```

Expand Down
7 changes: 2 additions & 5 deletions examples/coquille_context/__main__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
from coquille import Coquille
from coquille.sequences import bold
from coquille.sequences import fg_magenta
from coquille.sequences import italic

print("Hello World!")

# By default, the coquille wraps the standard output
with Coquille.new(fg_magenta, italic) as coquille:
with Coquille.new("fg_magenta", "italic") as coquille:
print("Hello World, but in magenta and italic!")
coquille.apply(bold)
coquille.apply("bold")
print("Now, with a touch of bold :D")

print("Oh, we are back to normal now...")
8 changes: 2 additions & 6 deletions examples/write/__main__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
from coquille import write
from coquille.sequences import bold
from coquille.sequences import fg_blue
from coquille.sequences import fg_magenta
from coquille.sequences import italic

print("Hello World!")

write("Hello World, but in magenta and italic!", fg_magenta, italic)
write("Hello World, but in magenta and italic!", "fg_magenta", "italic")

with open("examples/write/output.txt", "w") as my_file:
write("A pretty Hello World in a file!", fg_blue, bold, file=my_file)
write("A pretty Hello World in a file!", "fg_blue", "bold", file=my_file)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "Coquille"
version = "1.1.2"
version = "1.2.0"
authors = [{ name = "Qexat" }]
description = "Coquille is a library that wraps terminal escape sequences as convenient functions."
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion src/coquille/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from coquille.coquille import *
from coquille.prelude import *
39 changes: 28 additions & 11 deletions src/coquille/coquille.py → src/coquille/prelude.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,19 @@
from typing import TYPE_CHECKING

from coquille.sequences import EscapeSequence
from coquille.sequences import EscapeSequenceName
from coquille.sequences import get_sequence_from_name
from coquille.sequences import soft_reset

__all__ = ["apply", "Coquille", "EscapeSequence", "prepare", "write"]
__all__ = [
"apply",
"Coquille",
"EscapeSequence",
"EscapeSequenceName",
"prepare",
"write",
]


# ... don't say anything.
if TYPE_CHECKING: # pragma: no cover
Expand All @@ -26,7 +36,9 @@


@overload
def prepare(sequence: EscapeSequence) -> EscapeSequence: # pragma: no cover
def prepare(
sequence: EscapeSequence | EscapeSequenceName,
) -> EscapeSequence: # pragma: no cover
pass


Expand All @@ -40,7 +52,7 @@ def prepare(


def prepare(
sequence: EscapeSequence | Callable[P, EscapeSequence],
sequence: EscapeSequence | EscapeSequenceName | Callable[P, EscapeSequence],
*args: P.args,
**kwargs: P.kwargs,
) -> EscapeSequence:
Expand All @@ -51,15 +63,17 @@ def prepare(
the arguments to the escape sequence factory to construct one.
"""

if isinstance(sequence, str):
if isinstance(sequence, EscapeSequence):
return sequence
elif isinstance(sequence, str):
return get_sequence_from_name(sequence)

return sequence(*args, **kwargs)


@overload
def apply(
sequence: EscapeSequence,
sequence: EscapeSequence | EscapeSequenceName,
file: SupportsWrite[str] | None = None,
) -> None: # pragma: no cover
pass
Expand All @@ -76,7 +90,7 @@ def apply(


def apply(
sequence: EscapeSequence | Callable[P, EscapeSequence],
sequence: EscapeSequence | EscapeSequenceName | Callable[P, EscapeSequence],
file: SupportsWrite[str] | None = None,
*args: P.args,
**kwargs: P.kwargs,
Expand Down Expand Up @@ -109,7 +123,7 @@ class _ContextCoquille:
sequences: list[EscapeSequence]
file: SupportsWrite[str] | None

def apply(self, sequence: EscapeSequence) -> None:
def apply(self, sequence: EscapeSequence | EscapeSequenceName) -> None:
"""
Apply an escape sequence in the context manager of a Coquille
in live.
Expand Down Expand Up @@ -155,22 +169,25 @@ class Coquille:

@overload
@classmethod
def new(cls: type[Self], *sequences: EscapeSequence) -> Self: # pragma: no cover
def new(
cls: type[Self],
*sequences: EscapeSequence | EscapeSequenceName,
) -> Self: # pragma: no cover
pass

@overload
@classmethod
def new(
cls: type[Self],
*sequences: EscapeSequence,
*sequences: EscapeSequence | EscapeSequenceName,
file: SupportsWrite[str],
) -> Self: # pragma: no cover
pass

@classmethod
def new(
cls: type[Self],
*sequences: EscapeSequence,
*sequences: EscapeSequence | EscapeSequenceName,
file: SupportsWrite[str] | None = None,
) -> Self:
"""
Expand Down Expand Up @@ -264,7 +281,7 @@ def __exit__(self, *_) -> None:

def write(
text: str,
*sequences: EscapeSequence,
*sequences: EscapeSequence | EscapeSequenceName,
end: str | None = "\n",
file: SupportsWrite[str] | None = None,
) -> None:
Expand Down
22 changes: 20 additions & 2 deletions src/coquille/sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
- [RS] = rarely (never, basically) supported.
"""
from typing import Literal
from typing import NewType


# Constants
Expand All @@ -39,10 +38,14 @@


# Helper types
EscapeSequence = NewType("EscapeSequence", str)
EscapeSequenceName = str
AltFontNumber = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9]


class EscapeSequence(str):
pass


def escape_sequence(
code: str,
subcode: str | None = None,
Expand Down Expand Up @@ -461,3 +464,18 @@ def DCHARSET(subcode: str) -> EscapeSequence:

# aliases
DECSTR = soft_reset


def get_sequence_from_name(name: str) -> EscapeSequence:
module_items = dict(globals())
sequence_error = ValueError(f"{name!r} is not a valid escape sequence name")

if name not in module_items:
raise sequence_error

sequence = module_items[name]

if not isinstance(sequence, EscapeSequence):
raise sequence_error

return sequence
5 changes: 4 additions & 1 deletion tests/coquille_test.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from io import StringIO

import pytest
from coquille.coquille import *
from coquille.prelude import *
from coquille.sequences import DEC_save_cursor
from coquille.sequences import erase_in_display
from coquille.sequences import fg_black
from coquille.sequences import select_graphical_rendition
from coquille.sequences import start_of_string

Expand All @@ -12,6 +13,7 @@
["args", "output"],
[
((DEC_save_cursor,), DEC_save_cursor),
(("fg_black",), fg_black),
((start_of_string,), "\u001bX"),
((erase_in_display, 2), "\u001b[2J"),
((select_graphical_rendition, 38, 5, 16), "\x1b[38;5;16m"),
Expand All @@ -26,6 +28,7 @@ def test_prepare(args, output):
[
(DEC_save_cursor, (), DEC_save_cursor),
(start_of_string, (), "\u001bX"),
("fg_black", (), fg_black),
(erase_in_display, (2,), "\u001b[2J"),
(select_graphical_rendition, (38, 5, 16), "\x1b[38;5;16m"),
],
Expand Down

0 comments on commit ea7fa05

Please sign in to comment.