temparse 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- temparse/__init__.py +110 -0
- temparse/py.typed +0 -0
- temparse-0.0.1.dist-info/METADATA +116 -0
- temparse-0.0.1.dist-info/RECORD +5 -0
- temparse-0.0.1.dist-info/WHEEL +4 -0
temparse/__init__.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import functools
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import re
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from string.templatelib import Interpolation, Template
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
__all__ = ["Conversion", "FormatConversion", "Parser", "parse"]
|
|
11
|
+
|
|
12
|
+
log = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Parser[*T]:
|
|
16
|
+
def __init__(self, template: Template):
|
|
17
|
+
self.template = template
|
|
18
|
+
self.expression = f"^{
|
|
19
|
+
''.join(
|
|
20
|
+
re.escape(item) if isinstance(item, str) else r'(.+?)'
|
|
21
|
+
for item in template
|
|
22
|
+
)
|
|
23
|
+
}$"
|
|
24
|
+
log.debug(f"match expression: {self.expression!r}")
|
|
25
|
+
|
|
26
|
+
self._match_re = re.compile(self.expression)
|
|
27
|
+
|
|
28
|
+
def parse(self, s: str) -> tuple[*T]:
|
|
29
|
+
m = self._match_re.match(s)
|
|
30
|
+
if m is None:
|
|
31
|
+
raise ValueError(f"Invalid format: {s!r}")
|
|
32
|
+
|
|
33
|
+
return tuple(
|
|
34
|
+
_convert(text, interpolation)
|
|
35
|
+
for text, interpolation in zip(m.groups(), self.template.interpolations)
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class parse[*T]:
|
|
40
|
+
"""
|
|
41
|
+
Used to replace this function until [PEP 718](https://peps.python.org/pep-0718/) is accepted.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
def parse[*T](t: Template, s: str) -> tuple[*T]:
|
|
45
|
+
return Parser(t).parse(s)
|
|
46
|
+
```
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __new__(cls, t: Template, s: str) -> tuple[*T]:
|
|
50
|
+
return Parser(t).parse(s)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Conversion[T]:
|
|
54
|
+
__name__: str
|
|
55
|
+
__qualname__: str
|
|
56
|
+
|
|
57
|
+
def __init__(self, func: Callable[[str], T]) -> None:
|
|
58
|
+
self._convert = func
|
|
59
|
+
functools.update_wrapper(self, func)
|
|
60
|
+
|
|
61
|
+
def __call__(self, s: str) -> T:
|
|
62
|
+
return self._convert(s)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class FormatConversion[T]:
|
|
66
|
+
__name__: str
|
|
67
|
+
__qualname__: str
|
|
68
|
+
|
|
69
|
+
def __init__(self, func: Callable[[str, str], T]) -> None:
|
|
70
|
+
self._convert = func
|
|
71
|
+
functools.update_wrapper(self, func)
|
|
72
|
+
|
|
73
|
+
def __call__(self, s: str, format: str) -> T:
|
|
74
|
+
return self._convert(s, format)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _convert(s: str, i: Interpolation[Any]) -> Any:
|
|
78
|
+
match i.value:
|
|
79
|
+
case Conversion():
|
|
80
|
+
return i.value(s)
|
|
81
|
+
|
|
82
|
+
case FormatConversion():
|
|
83
|
+
return i.value(s, i.format_spec)
|
|
84
|
+
|
|
85
|
+
case datetime.datetime:
|
|
86
|
+
return datetime.datetime.strptime(s, i.format_spec).astimezone(datetime.UTC)
|
|
87
|
+
|
|
88
|
+
case datetime.date:
|
|
89
|
+
return datetime.date.strptime(s, i.format_spec)
|
|
90
|
+
|
|
91
|
+
case datetime.time:
|
|
92
|
+
return datetime.time.strptime(s, i.format_spec)
|
|
93
|
+
|
|
94
|
+
case _ if i.value is int:
|
|
95
|
+
return int(s, base=int(i.format_spec) if i.format_spec else 0)
|
|
96
|
+
|
|
97
|
+
case _ if i.value is float:
|
|
98
|
+
return float(s)
|
|
99
|
+
|
|
100
|
+
case _ if i.value is complex:
|
|
101
|
+
return complex(s)
|
|
102
|
+
|
|
103
|
+
case _ if i.value is str:
|
|
104
|
+
return s
|
|
105
|
+
|
|
106
|
+
case _ if i.value is json:
|
|
107
|
+
return json.loads(s)
|
|
108
|
+
|
|
109
|
+
case _:
|
|
110
|
+
raise TypeError(f"unkown object: {i.value}")
|
temparse/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: temparse
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: temparse is template + parse
|
|
5
|
+
Author: jiang-zhexin
|
|
6
|
+
Author-email: jiang-zhexin <162887873+jiang-zhexin@users.noreply.github.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Environment :: Web Environment
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
13
|
+
Requires-Python: >=3.14
|
|
14
|
+
Project-URL: homepage, https://github.com/jiang-zhexin/temparse
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# temparse
|
|
18
|
+
|
|
19
|
+
**temparse = template + parse**, parse strings using t-string templates.
|
|
20
|
+
|
|
21
|
+
Inspired by [parse](https://github.com/r1chardj0n3s/parse), but built on Python
|
|
22
|
+
3.14's [t-strings](https://peps.python.org/pep-0750/), with better type hints.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### uv
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv add temparse
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### pip
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Requires Python >= 3.14.
|
|
36
|
+
pip install temparse
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from temparse import parse
|
|
43
|
+
|
|
44
|
+
city, year = parse[str, int](
|
|
45
|
+
t"I live in {str}, since {int}", "I live in Tokyo, since 2010"
|
|
46
|
+
)
|
|
47
|
+
assert city == "Tokyo"
|
|
48
|
+
assert year == 2010
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The return type is `tuple[str, int]`.
|
|
52
|
+
|
|
53
|
+
## Supported Types
|
|
54
|
+
|
|
55
|
+
| Interpolation | Example | Output |
|
|
56
|
+
| --------------------------------------- | ------------------------ | -------------------- |
|
|
57
|
+
| `{str}` | `"hello"` | `"hello"` |
|
|
58
|
+
| `{int}` | `"42"` | `42` |
|
|
59
|
+
| `{int}` | `"0xff"` | `255` |
|
|
60
|
+
| `{int:16}` | `"ff"` | `255` |
|
|
61
|
+
| `{float}` | `"3.14"` | `3.14` |
|
|
62
|
+
| `{complex}` | `"-1.23+4.5j"` | `-1.23+4.5j` |
|
|
63
|
+
| `{json}` | `'[1,2,3]'`, `'{"a":1}'` | `[1,2,3]`, `{"a":1}` |
|
|
64
|
+
| `{datetime.datetime:%d/%m/%y %H:%M:%S}` | `"31/01/22 23:59:59"` | `datetime` |
|
|
65
|
+
| `{datetime.date:%Y-%m-%d}` | `"2024-03-15"` | `date` |
|
|
66
|
+
| `{datetime.time:%H:%M:%S}` | `"13:23:27"` | `time` |
|
|
67
|
+
|
|
68
|
+
## Custom Conversions
|
|
69
|
+
|
|
70
|
+
Decorate a function with `@Conversion` to use it directly in a template:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from temparse import Conversion, parse
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@Conversion
|
|
77
|
+
def upper(s: str) -> str:
|
|
78
|
+
return s.upper()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
(result,) = parse[str](t"{upper}", "hello")
|
|
82
|
+
assert result == "HELLO"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
When your converter needs the format spec as well, use `FormatConversion`:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from temparse import FormatConversion, parse
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@FormatConversion
|
|
92
|
+
def between(s: str, spec: str) -> str:
|
|
93
|
+
lo, hi = spec.split(",")
|
|
94
|
+
return s[int(lo) : int(hi)]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
(result,) = parse[str](t"{between:2,5}", "abcdefg")
|
|
98
|
+
assert result == "cde"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## `Parser` (Compiled Templates)
|
|
102
|
+
|
|
103
|
+
Build a parser once and reuse it:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from temparse import Parser
|
|
107
|
+
|
|
108
|
+
parser = Parser[str, int, float](t"{str} + {int} = {float}")
|
|
109
|
+
|
|
110
|
+
assert parser.parse("foo + 3 = 3.14") == ("foo", 3, 3.14)
|
|
111
|
+
assert parser.parse("bar + 7 = 2.72") == ("bar", 7, 2.72)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
temparse/__init__.py,sha256=CjLr0CIDsQAQlvswMT41KlX0IPhCLCLQXEzx_WFGDks,2958
|
|
2
|
+
temparse/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
temparse-0.0.1.dist-info/WHEEL,sha256=Q9FtwzuR2QE37l-JIkuyklGnJJiCBHKnsPVQ9vzCMzQ,81
|
|
4
|
+
temparse-0.0.1.dist-info/METADATA,sha256=kQaH9M5WkFX0eBYDz2EH8xop_w9bQBJDh-uiR_NnLQA,3292
|
|
5
|
+
temparse-0.0.1.dist-info/RECORD,,
|