lazy-static 1.0.0__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.
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lazy_static
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: lazy module constants -- think lazy imports but for assignments
|
|
5
|
+
Home-page: https://github.com/asottile/lazy-static
|
|
6
|
+
Author: Anthony Sottile
|
|
7
|
+
Author-email: asottile@umich.edu
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
12
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
13
|
+
Requires-Python: >=3.15
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
[](https://github.com/asottile/lazy-static/actions/workflows/main.yml)
|
|
19
|
+
[](https://results.pre-commit.ci/latest/github/asottile/lazy-static/main)
|
|
20
|
+
|
|
21
|
+
lazy-static
|
|
22
|
+
===========
|
|
23
|
+
|
|
24
|
+
lazy module constants -- think lazy imports but for assignments
|
|
25
|
+
|
|
26
|
+
roughly named after the (deprecated) rust [crate lazy_static]
|
|
27
|
+
|
|
28
|
+
[crate lazy_static]: https://docs.rs/lazy_static/latest/lazy_static/
|
|
29
|
+
|
|
30
|
+
## installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install lazy-static
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## why ?
|
|
37
|
+
|
|
38
|
+
python 3.15 adds [lazy imports] which are neat but are a little too easy to
|
|
39
|
+
accidentally make eager.
|
|
40
|
+
|
|
41
|
+
[lazy imports]: https://peps.python.org/pep-0810/
|
|
42
|
+
|
|
43
|
+
take this small example for a little wrapper around `pyyaml`:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import functools
|
|
47
|
+
|
|
48
|
+
lazy import yaml
|
|
49
|
+
|
|
50
|
+
loads = functools.partial(yaml.load, Loader=yaml.CSafeLoader)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
did you catch the bug? yeah that import isn't lazy due to accessing attributes!
|
|
54
|
+
|
|
55
|
+
it would be great if I could do:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
lazy loads = functools.partial(yaml.load, Loader=yaml.CSafeLoader)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
but there's no such thing...[^1] unless...
|
|
62
|
+
|
|
63
|
+
[^1]: yes yes you can do stuff with `@functools.cache` but that adds an ugly function call!
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
`lazy-static` adds a single api: `@lazy_static.lazy`
|
|
68
|
+
|
|
69
|
+
taking a simple example:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import argparse
|
|
73
|
+
from lazy_static import lazy
|
|
74
|
+
|
|
75
|
+
@lazy
|
|
76
|
+
def computed_once() -> int:
|
|
77
|
+
print('computing!')
|
|
78
|
+
return 5 * 5 * 5
|
|
79
|
+
|
|
80
|
+
def main() -> int:
|
|
81
|
+
parser = argparse.ArgumentParser()
|
|
82
|
+
parser.parse_args() # just for `--help`
|
|
83
|
+
print(f'got {computed_once}')
|
|
84
|
+
return 0
|
|
85
|
+
|
|
86
|
+
if __name__ == '__main__':
|
|
87
|
+
raise SystemExit(main())
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
the lazy attribute is deferred when not accessed:
|
|
91
|
+
|
|
92
|
+
```console
|
|
93
|
+
$ python3 t.py --help
|
|
94
|
+
usage: t.py [-h]
|
|
95
|
+
|
|
96
|
+
options:
|
|
97
|
+
-h, --help show this help message and exit
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
but acts like a normal variable otherwise!
|
|
101
|
+
|
|
102
|
+
```console
|
|
103
|
+
$ python3 t.py
|
|
104
|
+
computing!
|
|
105
|
+
got 125
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
it even works with static typing!
|
|
109
|
+
|
|
110
|
+
```diff
|
|
111
|
+
$ diff -u t.py.bak t.py
|
|
112
|
+
--- t.py.bak 2026-07-24 17:47:14.278681851 -0400
|
|
113
|
+
+++ t.py 2026-07-24 17:47:22.759961815 -0400
|
|
114
|
+
@@ -10,6 +10,7 @@
|
|
115
|
+
parser = argparse.ArgumentParser()
|
|
116
|
+
parser.parse_args() # just for `--help`
|
|
117
|
+
print(f'got {computed_once}')
|
|
118
|
+
+ reveal_type(computed_once)
|
|
119
|
+
return 0
|
|
120
|
+
|
|
121
|
+
if __name__ == '__main__':
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```console
|
|
125
|
+
$ mypy t.py
|
|
126
|
+
t.py:13: note: Revealed type is "int"
|
|
127
|
+
Success: no issues found in 1 source file
|
|
128
|
+
```
|
|
129
|
+
___
|
|
130
|
+
|
|
131
|
+
if we take the earlier example we can define our `loads` partial lazily while
|
|
132
|
+
preserving the `lazy` import!
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
import functools
|
|
137
|
+
|
|
138
|
+
from lazy_static import lazy
|
|
139
|
+
lazy import yaml
|
|
140
|
+
|
|
141
|
+
@lazy
|
|
142
|
+
def loads():
|
|
143
|
+
return functools.partial(yaml.loads, Loader=yaml.CSafeLoader)
|
|
144
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
lazy_static.py,sha256=J4HRY0h1PsE0I3-sjcHsL2zc_9U_c11O1BBsY_WDIUM,1225
|
|
2
|
+
lazy_static-1.0.0.dist-info/licenses/LICENSE,sha256=8VC67N75H-PlrFgJkcqutXaQpE-gNWIH4dwPt4OmyRc,1059
|
|
3
|
+
lazy_static-1.0.0.dist-info/METADATA,sha256=3Y5HnTiM4BaiM8YWObmBJD9Kf3TxQg3JplTzQpXujLo,3350
|
|
4
|
+
lazy_static-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
5
|
+
lazy_static-1.0.0.dist-info/top_level.txt,sha256=61kD7OSa4FU45IrnzGDt8zpYC22m8fXf2blhvEarurk,12
|
|
6
|
+
lazy_static-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 Anthony Sottile
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lazy_static
|
lazy_static.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import importlib.abc
|
|
3
|
+
import importlib.machinery
|
|
4
|
+
import importlib.util
|
|
5
|
+
import sys
|
|
6
|
+
import types
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class _LazyStaticFinder(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
|
11
|
+
def __init__(self) -> None:
|
|
12
|
+
self._funcs: dict[str, Callable[[], object]] = {}
|
|
13
|
+
|
|
14
|
+
def find_spec(
|
|
15
|
+
self,
|
|
16
|
+
fullname: str,
|
|
17
|
+
path: object,
|
|
18
|
+
target: object = None,
|
|
19
|
+
) -> importlib.machinery.ModuleSpec | None:
|
|
20
|
+
if fullname in self._funcs:
|
|
21
|
+
return importlib.util.spec_from_loader(fullname, self)
|
|
22
|
+
else:
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
def create_module(self, spec: object) -> None:
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
def exec_module(self, mod: types.ModuleType) -> None:
|
|
29
|
+
mod.V = self._funcs[mod.__name__]() # type: ignore[attr-defined]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@functools.cache
|
|
33
|
+
def _insert_finder() -> _LazyStaticFinder:
|
|
34
|
+
finder = _LazyStaticFinder()
|
|
35
|
+
sys.meta_path.append(finder)
|
|
36
|
+
return finder
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def lazy[T](f: Callable[[], T]) -> T:
|
|
40
|
+
name = f'{__name__}___{f.__module__}___{f.__name__}'.replace('.', '__')
|
|
41
|
+
|
|
42
|
+
g: dict[str, T] = {}
|
|
43
|
+
exec(f'lazy from {name} import V', g)
|
|
44
|
+
|
|
45
|
+
_insert_finder()._funcs[name] = f
|
|
46
|
+
|
|
47
|
+
return g['V']
|