Skip to content

Commit

Permalink
Fix confusing behavior (#29)
Browse files Browse the repository at this point in the history
* New `CoquilleLike` interface to avoid code duplication
* `_ContextCoquille` attributes are now "public" (to implement `CoquilleLike` correctly)
even though the class itself is private
* `Coquille` has now a `print` method (same as `_ContextCoquille`'s one)
* `Coquille.write()` has breaking changes: it is no longer a
staticmethod (see `write` function instead), and uses the coquille's registered
sequences
* The standalone `write` function is not an alias of
`Coquille.write()` anymore
* Bump to 1.1.0

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

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 16, 2023
1 parent 6503044 commit 27b5b17
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 41 deletions.
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.0.2"
version = "1.1.0"
authors = [{ name = "Qexat" }]
description = "Coquille is a library that wraps terminal escape sequences as convenient functions."
readme = "README.md"
Expand Down
126 changes: 87 additions & 39 deletions src/coquille/coquille.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
from __future__ import annotations

import sys
from abc import abstractmethod
from collections.abc import Callable
from dataclasses import dataclass
from typing import overload
from typing import Protocol
from typing import TYPE_CHECKING

from coquille.sequences import EscapeSequence
Expand Down Expand Up @@ -88,34 +90,24 @@ def apply(
target.write(string)


class _ContextCoquille:
__slots__ = ("__sequences", "__file") # private slots
class CoquilleLike(Protocol):
sequences: list[EscapeSequence]
file: SupportsWrite[str] | None

def __init__(
@abstractmethod
def print(
self,
sequences: list[EscapeSequence],
file: SupportsWrite[str] | None,
*values: object,
sep: str | None = None,
end: str | None = "\n",
) -> None:
self.__sequences = sequences
self.__file = file

@property
def sequences(self) -> list[EscapeSequence]:
"""
Read-only ; the base sequences that were applied at the
beginning of the `with` block. They are reset when the
block ends.
"""
pass

return self.__sequences

@property
def file(self) -> SupportsWrite[str] | None:
"""
Read-only ; the file where the sequences are printed in.
"""

return self.__file
@dataclass(slots=True)
class _ContextCoquille:
sequences: list[EscapeSequence]
file: SupportsWrite[str] | None

def apply(self, sequence: EscapeSequence) -> None:
"""
Expand Down Expand Up @@ -153,7 +145,7 @@ def print(
```
"""

print(*values, sep=sep, end=end, file=self.file)
Coquille.print(self, *values, sep=sep, end=end)


@dataclass(slots=True)
Expand Down Expand Up @@ -187,28 +179,52 @@ def new(

return cls(list(sequences), file)

@staticmethod
def print(
self: CoquilleLike,
*values: object,
sep: str | None = " ",
end: str | None = "\n",
) -> None:
"""
Convenient function to print in the same file as the coquille's one.
## Example
```py
>>> my_coquille = Coquille.new(bold, fg_red, file=sys.stderr)
>>> # same as: print("My pretty error message", file=my_coquille.file)
>>> my_coquille.print("My pretty error message")
```
"""

for sequence in self.sequences:
apply(sequence, self.file)

print(*values, sep=sep, end=end, file=self.file)
apply(soft_reset)

def write(
self,
text: str,
*sequences: EscapeSequence,
end: str | None = "\n",
file: SupportsWrite[str] | None = None,
) -> None:
"""
A function relatively similar to built-in `print`, but with
support of escape sequences that are prepended to the printed
text.
A function relatively similar to built-in `print`.
It is the same as naked `write`, but it uses the coquille's
registered sequences.
Example:
```py
>>> from coquille import Coquille
>>> from coquille.sequences import fg_magenta, italic
>>> Coquille.write("Hello World!", fg_magenta, italic)
>>> my_coquille = Coquille.new(fg_magenta, italic)
>>> my_coquille.write("Hello World!")
Hello World!
```
Here, "Hello World!" is printed in italic and magenta, but this
cannot be reproduced exactly in docstrings.
The previous example is roughly the same as doing:
The previous example is roughly equivalent to:
```py
>>> print("\x1b[35m", end="")
>>> print("\x1b[3m", end="")
Expand All @@ -220,13 +236,9 @@ def write(
because the range of allowed escape sequences is larger than SGR.
"""

for sequence in sequences:
apply(sequence, file)

print(text, end=end, file=file)
apply(soft_reset)
self.print(text, end=end)

def __enter__(self):
def __enter__(self) -> CoquilleLike:
"""
Set up a context for a Coquille.
Expand All @@ -250,4 +262,40 @@ def __exit__(self, *_) -> None:
apply(soft_reset, self.file)


write = Coquille.write
def write(
text: str,
*sequences: EscapeSequence,
end: str | None = "\n",
file: SupportsWrite[str] | None = None,
) -> None:
"""
A function relatively similar to built-in `print`, but with
support of escape sequences that are prepended to the printed
text.
Example:
```py
>>> from coquille.sequences import fg_magenta, italic
>>> Coquille.write("Hello World!", fg_magenta, italic)
Hello World!
```
Here, "Hello World!" is printed in italic and magenta, but this
cannot be reproduced exactly in docstrings.
The previous example is roughly the same as doing:
```py
>>> print("\x1b[35m", end="")
>>> print("\x1b[3m", end="")
>>> print("Hello World!")
>>> print("\x1b[!p", end="")
```
Note that the soft reset sequence is used rather than SGR reset `x1b[0m`,
because the range of allowed escape sequences is larger than SGR.
"""

for sequence in sequences:
apply(sequence, file)

print(text, end=end, file=file)
apply(soft_reset)
4 changes: 3 additions & 1 deletion src/coquille/typeshed.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Typeshed stuff that Coquille needs but that are not available
on the Python standard library.
"""
from abc import abstractmethod
from typing import Protocol
from typing import TypeVar

Expand All @@ -10,8 +11,9 @@


class SupportsWrite(Protocol[_T_contra]):
@abstractmethod
def write(self, __s: _T_contra) -> object:
...
pass


Self = TypeVar("Self")

0 comments on commit 27b5b17

Please sign in to comment.