Skip to content

Commit

Permalink
no pth hook for coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
rmorshea committed Apr 22, 2023
1 parent 0d0a9c2 commit 580c88a
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 57 deletions.
7 changes: 5 additions & 2 deletions hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ checks = [
"hatch run lint:all",
"hatch run test:all",
]

fixes = [
"hatch run lint:fix",
]

[envs.lint]
skip-install = true
dependencies = ["ruff", "black", "mypy"]

[envs.lint.scripts]
Expand All @@ -42,6 +45,6 @@ dependencies = ["pytest", "coverage"]
all = ["pass", "cover"]
pass = "pytest tests"
cover = [
"coverage run -m pytest tests",
"TAGSTR_DISABLE_IMPORT_HOOK=true coverage run -m pytest tests",
"coverage report",
]
2 changes: 1 addition & 1 deletion src/tagstr.pth
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import tagstr
import os; import importlib; os.getenv("TAGSTR_DISABLE_IMPORT_HOOK", "false").lower() != "true" and importlib.import_module("tagstr");
18 changes: 15 additions & 3 deletions src/tagstr/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import os

from tagstr.decorator import tagfunc
from tagstr.utils import Thunk, decode_raw, format_value
from tagstr.types import TagFunc, Thunk
from tagstr.utils import decode_raw, format_value

if os.getenv("TAGSTR_DISABLE_IMPORT_HOOK", "false").lower() != "true":
import tagstr.importer # pragma: no cover # noqa

__version__ = "0.0.1"
__version__ = "0.1.0"

__all__ = ["tagfunc", "Thunk", "decode_raw", "format_value"]
__all__ = [
"decode_raw",
"format_value",
"tagfunc",
"TagFunc",
"Thunk",
]
38 changes: 38 additions & 0 deletions src/tagstr/_py_gte_310.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from __future__ import annotations

from typing import Iterator

from tagstr.types import Thunk


def decode_raw(*args: str | Thunk) -> Iterator[str | Thunk]:
"""Decode raw strings and thunks."""
for arg in args:
match arg:
case str():
yield arg.encode("utf-8").decode("unicode-escape")
case _:
yield arg


def format_value(arg: str | Thunk) -> str:
"""Format a value from a thunk or a string."""
match arg:
case str():
return arg
case getvalue, _, conv, spec:
value = getvalue()
match conv:
case "r":
value = repr(value)
case "s":
value = str(value)
case "a":
value = ascii(value)
case None:
pass
case _:
raise ValueError(f"Bad conversion: {conv!r}")
return format(value, spec if spec is not None else "")
case _:
raise ValueError(f"Cannot format {arg!r} - expected a thunk or a string")
36 changes: 36 additions & 0 deletions src/tagstr/_py_lt_310.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from __future__ import annotations

from typing import Iterator

from tagstr.types import Thunk


def decode_raw(*args: str | Thunk) -> Iterator[str | Thunk]:
"""Decode raw strings and thunks."""
for arg in args:
if isinstance(arg, str):
yield arg.encode("utf-8").decode("unicode-escape")
else:
yield arg


def format_value(arg: str | Thunk) -> str:
"""Format a value from a thunk or a string."""
if isinstance(arg, str):
return arg
elif isinstance(arg, tuple) and len(arg) == 4:
getvalue, _, conv, spec = arg
value = getvalue()
if conv == "r":
value = repr(value)
elif conv == "s":
value = str(value)
elif conv == "a":
value = ascii(value)
elif conv is None:
pass
else:
raise ValueError(f"Bad conversion: {conv!r}")
return format(value, spec if spec is not None else "")
else:
raise ValueError(f"Cannot format {arg!r} - expected a thunk or a string")
12 changes: 2 additions & 10 deletions src/tagstr/decorator.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from __future__ import annotations

from typing import Generic, Protocol, TypeVar
from typing import Generic, TypeVar

from tagstr.utils import Thunk
from tagstr.types import TagFunc, Thunk

T = TypeVar("T")

Expand All @@ -19,11 +19,3 @@ def __matmul__(self, other: str) -> T:

def __call__(self, *args: str | Thunk) -> T:
return self.func(*args)


T_co = TypeVar("T_co", covariant=True)


class TagFunc(Protocol[T_co]):
def __call__(self, *args: str | Thunk) -> T_co:
...
23 changes: 23 additions & 0 deletions src/tagstr/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from __future__ import annotations

from typing import Any, Callable, Protocol, TypeAlias, TypeVar

Thunk: TypeAlias = "tuple[Callable[[], Any], str, str | None, str | None]"
"""
A "thunk" is a tuple contianing the following:
1. getvalue: a callable that returns the value to be formatted
2. raw: the raw string that was used to create the thunk
3. conv: the conversion character (e.g. "r", "s", "a")
4. formatspec: the format specification (e.g. ".2f")
TODO: thunks likely should like be a namedtuple in the future.
"""


T_co = TypeVar("T_co", covariant=True)


class TagFunc(Protocol[T_co]):
def __call__(self, *args: str | Thunk) -> T_co:
...
47 changes: 6 additions & 41 deletions src/tagstr/utils.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,8 @@
from typing import Any, Callable, Iterator
import sys

# TODO: thunks likely should have a "tuple-like object with named attributes"
# (so namedtuples) as seen in the os module. This will enable future expansion.
# Of course such named attribute support can also be done in the future!
Thunk = tuple[
Callable[[], Any], # getvalue
str, # raw
str | None, # conv
str | None, # formatspec
]
if sys.version_info < (3, 10):
from tagstr._py_lt_310 import decode_raw, format_value
else:
from tagstr._py_gte_310 import decode_raw, format_value


def decode_raw(*args: str | Thunk) -> Iterator[str | Thunk]:
"""Decode raw strings and thunks."""
for arg in args:
if isinstance(arg, str):
yield arg.encode("utf-8").decode("unicode-escape")
else:
yield arg


def format_value(arg: str | Thunk) -> str:
"""Format a value from a thunk or a string."""
match arg:
case str():
return arg
case getvalue, _, conv, spec:
value = getvalue()
match conv:
case "r":
value = repr(value)
case "s":
value = str(value)
case "a":
value = ascii(value)
case None:
pass
case _:
raise ValueError(f"Bad conversion: {conv!r}")
return format(value, spec if spec is not None else "")
case _:
raise ValueError(f"Cannot format {arg!r} - expected a thunk or a string")
__all__ = ["format_value", "decode_raw"]
3 changes: 3 additions & 0 deletions temp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import tagstr # noqa

print @ f"asd {1}"

0 comments on commit 580c88a

Please sign in to comment.