propcache 0.3.0__tar.gz → 0.3.2__tar.gz
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.
- {propcache-0.3.0 → propcache-0.3.2}/.coveragerc +4 -1
- {propcache-0.3.0 → propcache-0.3.2}/CHANGES.rst +55 -0
- {propcache-0.3.0/src/propcache.egg-info → propcache-0.3.2}/PKG-INFO +58 -2
- {propcache-0.3.0 → propcache-0.3.2}/docs/api.rst +1 -1
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/_backend.py +20 -21
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/_compat.py +9 -14
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/_cython_configuration.py +29 -6
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/_transformers.py +8 -4
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/cli.py +5 -4
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/hooks.py +1 -1
- {propcache-0.3.0 → propcache-0.3.2}/pyproject.toml +0 -10
- propcache-0.3.2/requirements/cython.txt +1 -0
- {propcache-0.3.0 → propcache-0.3.2}/requirements/doc.txt +1 -1
- propcache-0.3.2/requirements/lint.txt +1 -0
- propcache-0.3.0/requirements/test-pure.txt → propcache-0.3.2/requirements/test.txt +2 -1
- {propcache-0.3.0 → propcache-0.3.2}/setup.cfg +2 -1
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache/__init__.py +1 -1
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache/_helpers.py +2 -2
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache/_helpers_c.pyx +2 -0
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache/_helpers_py.py +11 -7
- {propcache-0.3.0 → propcache-0.3.2/src/propcache.egg-info}/PKG-INFO +58 -2
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache.egg-info/SOURCES.txt +0 -3
- {propcache-0.3.0 → propcache-0.3.2}/tests/conftest.py +1 -1
- {propcache-0.3.0 → propcache-0.3.2}/tests/test_cached_property.py +18 -19
- {propcache-0.3.0 → propcache-0.3.2}/tests/test_under_cached_property.py +51 -13
- propcache-0.3.0/requirements/cython-freethreading.txt +0 -1
- propcache-0.3.0/requirements/cython.txt +0 -1
- propcache-0.3.0/requirements/lint.txt +0 -1
- propcache-0.3.0/requirements/test-freethreading.txt +0 -2
- propcache-0.3.0/requirements/test.txt +0 -2
- {propcache-0.3.0 → propcache-0.3.2}/CHANGES/.TEMPLATE.rst +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/CHANGES/.gitignore +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/CHANGES/README.rst +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/LICENSE +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/MANIFEST.in +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/NOTICE +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/README.rst +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/Makefile +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/_static/README.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/changes.rst +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/conf.py +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/contributing/guidelines.rst +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/contributing/release_guide.rst +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/index.rst +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/make.bat +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/docs/spelling_wordlist.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/packaging/README.md +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/__init__.py +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/packaging/pep517_backend/__main__.py +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/pytest.ini +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/requirements/codspeed.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/requirements/dev.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/requirements/doc-spelling.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/requirements/towncrier.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache/api.py +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache/py.typed +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache.egg-info/dependency_links.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache.egg-info/not-zip-safe +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/src/propcache.egg-info/top_level.txt +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/tests/test_api.py +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/tests/test_benchmarks.py +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/tests/test_init.py +0 -0
- {propcache-0.3.0 → propcache-0.3.2}/towncrier.toml +0 -0
|
@@ -13,7 +13,10 @@ _site-packages-to-src-mapping =
|
|
|
13
13
|
|
|
14
14
|
[report]
|
|
15
15
|
exclude_also =
|
|
16
|
-
|
|
16
|
+
if TYPE_CHECKING
|
|
17
|
+
assert False
|
|
18
|
+
: \.\.\.(\s*#.*)?$
|
|
19
|
+
^ +\.\.\.$
|
|
17
20
|
# small library, don't fail when running without C-extension
|
|
18
21
|
fail_under = 50.00
|
|
19
22
|
skip_covered = true
|
|
@@ -14,6 +14,61 @@ Changelog
|
|
|
14
14
|
|
|
15
15
|
.. towncrier release notes start
|
|
16
16
|
|
|
17
|
+
0.3.2
|
|
18
|
+
=====
|
|
19
|
+
|
|
20
|
+
*(2025-06-09)*
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Improved documentation
|
|
24
|
+
----------------------
|
|
25
|
+
|
|
26
|
+
- Fixed incorrect decorator usage in the :func:`~propcache.api.under_cached_property` example code -- by :user:`meanmail`.
|
|
27
|
+
|
|
28
|
+
*Related issues and pull requests on GitHub:*
|
|
29
|
+
:issue:`109`.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
Packaging updates and notes for downstreams
|
|
33
|
+
-------------------------------------------
|
|
34
|
+
|
|
35
|
+
- Updated to use Cython 3.1 universally across the build path -- by :user:`lysnikolaou`.
|
|
36
|
+
|
|
37
|
+
*Related issues and pull requests on GitHub:*
|
|
38
|
+
:issue:`117`.
|
|
39
|
+
|
|
40
|
+
- Made Cython line tracing opt-in via the ``with-cython-tracing`` build config setting -- by :user:`bdraco`.
|
|
41
|
+
|
|
42
|
+
Previously, line tracing was enabled by default in :file:`pyproject.toml`, which caused build issues for some users and made wheels nearly twice as slow.
|
|
43
|
+
|
|
44
|
+
Now line tracing is only enabled when explicitly requested via ``pip install . --config-setting=with-cython-tracing=true`` or by setting the ``PROPCACHE_CYTHON_TRACING`` environment variable.
|
|
45
|
+
|
|
46
|
+
*Related issues and pull requests on GitHub:*
|
|
47
|
+
:issue:`118`.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
----
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
0.3.1
|
|
54
|
+
=====
|
|
55
|
+
|
|
56
|
+
*(2025-03-25)*
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
Bug fixes
|
|
60
|
+
---------
|
|
61
|
+
|
|
62
|
+
- Improved typing annotations, fixing some type errors under correct usage
|
|
63
|
+
and improving typing robustness generally -- by :user:`Dreamsorcerer`.
|
|
64
|
+
|
|
65
|
+
*Related issues and pull requests on GitHub:*
|
|
66
|
+
:issue:`103`.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
----
|
|
70
|
+
|
|
71
|
+
|
|
17
72
|
0.3.0
|
|
18
73
|
=====
|
|
19
74
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: propcache
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Accelerated property cache
|
|
5
5
|
Home-page: https://github.com/aio-libs/propcache
|
|
6
6
|
Author: Andrew Svetlov
|
|
@@ -35,6 +35,7 @@ Requires-Python: >=3.9
|
|
|
35
35
|
Description-Content-Type: text/x-rst
|
|
36
36
|
License-File: LICENSE
|
|
37
37
|
License-File: NOTICE
|
|
38
|
+
Dynamic: license-file
|
|
38
39
|
|
|
39
40
|
propcache
|
|
40
41
|
=========
|
|
@@ -151,6 +152,61 @@ Changelog
|
|
|
151
152
|
|
|
152
153
|
.. towncrier release notes start
|
|
153
154
|
|
|
155
|
+
0.3.2
|
|
156
|
+
=====
|
|
157
|
+
|
|
158
|
+
*(2025-06-09)*
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
Improved documentation
|
|
162
|
+
----------------------
|
|
163
|
+
|
|
164
|
+
- Fixed incorrect decorator usage in the ``~propcache.api.under_cached_property`` example code -- by `@meanmail <https://github.com/sponsors/meanmail>`__.
|
|
165
|
+
|
|
166
|
+
*Related issues and pull requests on GitHub:*
|
|
167
|
+
`#109 <https://github.com/aio-libs/propcache/issues/109>`__.
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
Packaging updates and notes for downstreams
|
|
171
|
+
-------------------------------------------
|
|
172
|
+
|
|
173
|
+
- Updated to use Cython 3.1 universally across the build path -- by `@lysnikolaou <https://github.com/sponsors/lysnikolaou>`__.
|
|
174
|
+
|
|
175
|
+
*Related issues and pull requests on GitHub:*
|
|
176
|
+
`#117 <https://github.com/aio-libs/propcache/issues/117>`__.
|
|
177
|
+
|
|
178
|
+
- Made Cython line tracing opt-in via the ``with-cython-tracing`` build config setting -- by `@bdraco <https://github.com/sponsors/bdraco>`__.
|
|
179
|
+
|
|
180
|
+
Previously, line tracing was enabled by default in ``pyproject.toml``, which caused build issues for some users and made wheels nearly twice as slow.
|
|
181
|
+
|
|
182
|
+
Now line tracing is only enabled when explicitly requested via ``pip install . --config-setting=with-cython-tracing=true`` or by setting the ``PROPCACHE_CYTHON_TRACING`` environment variable.
|
|
183
|
+
|
|
184
|
+
*Related issues and pull requests on GitHub:*
|
|
185
|
+
`#118 <https://github.com/aio-libs/propcache/issues/118>`__.
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
----
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
0.3.1
|
|
192
|
+
=====
|
|
193
|
+
|
|
194
|
+
*(2025-03-25)*
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
Bug fixes
|
|
198
|
+
---------
|
|
199
|
+
|
|
200
|
+
- Improved typing annotations, fixing some type errors under correct usage
|
|
201
|
+
and improving typing robustness generally -- by `@Dreamsorcerer <https://github.com/sponsors/Dreamsorcerer>`__.
|
|
202
|
+
|
|
203
|
+
*Related issues and pull requests on GitHub:*
|
|
204
|
+
`#103 <https://github.com/aio-libs/propcache/issues/103>`__.
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
----
|
|
208
|
+
|
|
209
|
+
|
|
154
210
|
0.3.0
|
|
155
211
|
=====
|
|
156
212
|
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
|
-
import sysconfig
|
|
8
7
|
import typing as t
|
|
8
|
+
from collections.abc import Iterator
|
|
9
9
|
from contextlib import contextmanager, nullcontext, suppress
|
|
10
10
|
from functools import partial
|
|
11
11
|
from pathlib import Path
|
|
@@ -56,7 +56,7 @@ __all__ = ( # noqa: WPS410
|
|
|
56
56
|
'get_requires_for_build_wheel',
|
|
57
57
|
'prepare_metadata_for_build_wheel',
|
|
58
58
|
*(
|
|
59
|
-
() if _setuptools_build_editable is None
|
|
59
|
+
() if _setuptools_build_editable is None # type: ignore[redundant-expr]
|
|
60
60
|
else (
|
|
61
61
|
'build_editable',
|
|
62
62
|
'get_requires_for_build_editable',
|
|
@@ -87,7 +87,7 @@ PURE_PYTHON_MODE_CLI_FALLBACK = not IS_CPYTHON
|
|
|
87
87
|
"""A fallback for ``pure-python`` is not set."""
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
def _is_truthy_setting_value(setting_value) -> bool:
|
|
90
|
+
def _is_truthy_setting_value(setting_value: str) -> bool:
|
|
91
91
|
truthy_values = {'', None, 'true', '1', 'on'}
|
|
92
92
|
return setting_value.lower() in truthy_values
|
|
93
93
|
|
|
@@ -108,7 +108,7 @@ def _get_setting_value(
|
|
|
108
108
|
continue
|
|
109
109
|
|
|
110
110
|
with suppress(lookup_errors): # type: ignore[arg-type]
|
|
111
|
-
return _is_truthy_setting_value(src_mapping[src_key]) # type: ignore[index]
|
|
111
|
+
return _is_truthy_setting_value(src_mapping[src_key]) # type: ignore[arg-type,index]
|
|
112
112
|
|
|
113
113
|
return default
|
|
114
114
|
|
|
@@ -125,7 +125,7 @@ def _make_pure_python(config_settings: _ConfigDict | None = None) -> bool:
|
|
|
125
125
|
def _include_cython_line_tracing(
|
|
126
126
|
config_settings: _ConfigDict | None = None,
|
|
127
127
|
*,
|
|
128
|
-
default=False,
|
|
128
|
+
default: bool = False,
|
|
129
129
|
) -> bool:
|
|
130
130
|
return _get_setting_value(
|
|
131
131
|
config_settings,
|
|
@@ -136,7 +136,7 @@ def _include_cython_line_tracing(
|
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
@contextmanager
|
|
139
|
-
def patched_distutils_cmd_install():
|
|
139
|
+
def patched_distutils_cmd_install() -> Iterator[None]:
|
|
140
140
|
"""Make `install_lib` of `install` cmd always use `platlib`.
|
|
141
141
|
|
|
142
142
|
:yields: None
|
|
@@ -144,19 +144,19 @@ def patched_distutils_cmd_install():
|
|
|
144
144
|
# Without this, build_lib puts stuff under `*.data/purelib/` folder
|
|
145
145
|
orig_finalize = _distutils_install_cmd.finalize_options
|
|
146
146
|
|
|
147
|
-
def new_finalize_options(self
|
|
147
|
+
def new_finalize_options(self: _distutils_install_cmd) -> None:
|
|
148
148
|
self.install_lib = self.install_platlib
|
|
149
149
|
orig_finalize(self)
|
|
150
150
|
|
|
151
|
-
_distutils_install_cmd.finalize_options = new_finalize_options
|
|
151
|
+
_distutils_install_cmd.finalize_options = new_finalize_options # type: ignore[method-assign]
|
|
152
152
|
try:
|
|
153
153
|
yield
|
|
154
154
|
finally:
|
|
155
|
-
_distutils_install_cmd.finalize_options = orig_finalize
|
|
155
|
+
_distutils_install_cmd.finalize_options = orig_finalize # type: ignore[method-assign]
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
@contextmanager
|
|
159
|
-
def patched_dist_has_ext_modules():
|
|
159
|
+
def patched_dist_has_ext_modules() -> Iterator[None]:
|
|
160
160
|
"""Make `has_ext_modules` of `Distribution` always return `True`.
|
|
161
161
|
|
|
162
162
|
:yields: None
|
|
@@ -164,15 +164,15 @@ def patched_dist_has_ext_modules():
|
|
|
164
164
|
# Without this, build_lib puts stuff under `*.data/platlib/` folder
|
|
165
165
|
orig_func = _DistutilsDistribution.has_ext_modules
|
|
166
166
|
|
|
167
|
-
_DistutilsDistribution.has_ext_modules = lambda *args, **kwargs: True
|
|
167
|
+
_DistutilsDistribution.has_ext_modules = lambda *args, **kwargs: True # type: ignore[method-assign]
|
|
168
168
|
try:
|
|
169
169
|
yield
|
|
170
170
|
finally:
|
|
171
|
-
_DistutilsDistribution.has_ext_modules = orig_func
|
|
171
|
+
_DistutilsDistribution.has_ext_modules = orig_func # type: ignore[method-assign]
|
|
172
172
|
|
|
173
173
|
|
|
174
174
|
@contextmanager
|
|
175
|
-
def patched_dist_get_long_description():
|
|
175
|
+
def patched_dist_get_long_description() -> Iterator[None]:
|
|
176
176
|
"""Make `has_ext_modules` of `Distribution` always return `True`.
|
|
177
177
|
|
|
178
178
|
:yields: None
|
|
@@ -180,16 +180,17 @@ def patched_dist_get_long_description():
|
|
|
180
180
|
# Without this, build_lib puts stuff under `*.data/platlib/` folder
|
|
181
181
|
_orig_func = _DistutilsDistributionMetadata.get_long_description
|
|
182
182
|
|
|
183
|
-
def _get_sanitized_long_description(self):
|
|
183
|
+
def _get_sanitized_long_description(self: _DistutilsDistributionMetadata) -> str:
|
|
184
|
+
assert self.long_description is not None
|
|
184
185
|
return sanitize_rst_roles(self.long_description)
|
|
185
186
|
|
|
186
|
-
_DistutilsDistributionMetadata.get_long_description = (
|
|
187
|
+
_DistutilsDistributionMetadata.get_long_description = ( # type: ignore[method-assign]
|
|
187
188
|
_get_sanitized_long_description
|
|
188
189
|
)
|
|
189
190
|
try:
|
|
190
191
|
yield
|
|
191
192
|
finally:
|
|
192
|
-
_DistutilsDistributionMetadata.get_long_description = _orig_func
|
|
193
|
+
_DistutilsDistributionMetadata.get_long_description = _orig_func # type: ignore[method-assign]
|
|
193
194
|
|
|
194
195
|
|
|
195
196
|
def _exclude_dir_path(
|
|
@@ -291,9 +292,9 @@ def maybe_prebuild_c_extensions(
|
|
|
291
292
|
with build_dir_ctx:
|
|
292
293
|
config = _get_local_cython_config()
|
|
293
294
|
|
|
294
|
-
cythonize_args = _make_cythonize_cli_args_from_config(config)
|
|
295
|
+
cythonize_args = _make_cythonize_cli_args_from_config(config, cython_line_tracing_requested)
|
|
295
296
|
with _patched_cython_env(config['env'], cython_line_tracing_requested):
|
|
296
|
-
_cythonize_cli_cmd(cythonize_args)
|
|
297
|
+
_cythonize_cli_cmd(cythonize_args) # type: ignore[no-untyped-call]
|
|
297
298
|
with patched_distutils_cmd_install():
|
|
298
299
|
with patched_dist_has_ext_modules():
|
|
299
300
|
yield
|
|
@@ -374,10 +375,8 @@ def get_requires_for_build_wheel(
|
|
|
374
375
|
|
|
375
376
|
if is_pure_python_build:
|
|
376
377
|
c_ext_build_deps = []
|
|
377
|
-
elif sysconfig.get_config_var('Py_GIL_DISABLED'):
|
|
378
|
-
c_ext_build_deps = ['Cython ~= 3.1.0a1']
|
|
379
378
|
else:
|
|
380
|
-
c_ext_build_deps = ['Cython ~= 3.0
|
|
379
|
+
c_ext_build_deps = ['Cython ~= 3.1.0']
|
|
381
380
|
|
|
382
381
|
return _setuptools_get_requires_for_build_wheel(
|
|
383
382
|
config_settings=config_settings,
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
"""Cross-python stdlib shims."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import
|
|
4
|
+
import sys
|
|
5
|
+
from collections.abc import Iterator
|
|
5
6
|
from contextlib import contextmanager
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
# isort: off
|
|
9
|
-
|
|
10
|
-
from contextlib import chdir as chdir_cm
|
|
11
|
-
|
|
10
|
+
if sys.version_info >= (3, 11):
|
|
11
|
+
from contextlib import chdir as chdir_cm
|
|
12
|
+
from tomllib import loads as load_toml_from_string
|
|
13
|
+
else:
|
|
14
|
+
from tomli import loads as load_toml_from_string
|
|
12
15
|
|
|
13
|
-
@contextmanager
|
|
14
|
-
def chdir_cm(path: os.PathLike) ->
|
|
16
|
+
@contextmanager
|
|
17
|
+
def chdir_cm(path: os.PathLike) -> Iterator[None]:
|
|
15
18
|
"""Temporarily change the current directory, recovering on exit."""
|
|
16
19
|
original_wd = Path.cwd()
|
|
17
20
|
os.chdir(path)
|
|
@@ -22,12 +25,4 @@ except ImportError:
|
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
# isort: on
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
try:
|
|
28
|
-
from tomllib import loads as load_toml_from_string
|
|
29
|
-
except ImportError:
|
|
30
|
-
from tomli import loads as load_toml_from_string
|
|
31
|
-
|
|
32
|
-
|
|
33
28
|
__all__ = ("chdir_cm", "load_toml_from_string") # noqa: WPS410
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
from collections.abc import Iterator
|
|
6
7
|
from contextlib import contextmanager
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from sys import version_info as _python_version_tuple
|
|
10
|
+
from typing import TypedDict
|
|
9
11
|
|
|
10
12
|
from expandvars import expandvars
|
|
11
13
|
|
|
@@ -13,7 +15,14 @@ from ._compat import load_toml_from_string
|
|
|
13
15
|
from ._transformers import get_cli_kwargs_from_config, get_enabled_cli_flags_from_config
|
|
14
16
|
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
class Config(TypedDict):
|
|
19
|
+
env: dict[str, str]
|
|
20
|
+
flags: dict[str, bool]
|
|
21
|
+
kwargs: dict[str, str | dict[str, str]]
|
|
22
|
+
src: list[str]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_local_cython_config() -> Config:
|
|
17
26
|
"""Grab optional build dependencies from pyproject.toml config.
|
|
18
27
|
|
|
19
28
|
:returns: config section from ``pyproject.toml``
|
|
@@ -67,20 +76,34 @@ def get_local_cython_config() -> dict:
|
|
|
67
76
|
"""
|
|
68
77
|
config_toml_txt = (Path.cwd().resolve() / 'pyproject.toml').read_text()
|
|
69
78
|
config_mapping = load_toml_from_string(config_toml_txt)
|
|
70
|
-
return config_mapping['tool']['local']['cythonize']
|
|
79
|
+
return config_mapping['tool']['local']['cythonize'] # type: ignore[no-any-return]
|
|
71
80
|
|
|
72
81
|
|
|
73
|
-
def
|
|
82
|
+
def _configure_cython_line_tracing(config_kwargs: dict[str, str | dict[str, str]], cython_line_tracing_requested: bool) -> None:
|
|
83
|
+
"""Configure Cython line tracing directives if requested."""
|
|
84
|
+
# If line tracing is requested, add it to the directives
|
|
85
|
+
if cython_line_tracing_requested:
|
|
86
|
+
directives = config_kwargs.setdefault('directive', {})
|
|
87
|
+
assert isinstance(directives, dict) # Type narrowing for mypy
|
|
88
|
+
directives['linetrace'] = 'True'
|
|
89
|
+
directives['profile'] = 'True'
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def make_cythonize_cli_args_from_config(config: Config, cython_line_tracing_requested: bool = False) -> list[str]:
|
|
74
93
|
py_ver_arg = f'-{_python_version_tuple.major!s}'
|
|
75
94
|
|
|
76
95
|
cli_flags = get_enabled_cli_flags_from_config(config['flags'])
|
|
77
|
-
|
|
96
|
+
config_kwargs = config['kwargs']
|
|
97
|
+
|
|
98
|
+
_configure_cython_line_tracing(config_kwargs, cython_line_tracing_requested)
|
|
99
|
+
|
|
100
|
+
cli_kwargs = get_cli_kwargs_from_config(config_kwargs)
|
|
78
101
|
|
|
79
102
|
return cli_flags + [py_ver_arg] + cli_kwargs + ['--'] + config['src']
|
|
80
103
|
|
|
81
104
|
|
|
82
105
|
@contextmanager
|
|
83
|
-
def patched_env(env: dict[str, str], cython_line_tracing_requested: bool):
|
|
106
|
+
def patched_env(env: dict[str, str], cython_line_tracing_requested: bool) -> Iterator[None]:
|
|
84
107
|
"""Temporary set given env vars.
|
|
85
108
|
|
|
86
109
|
:param env: tmp env vars to set
|
|
@@ -89,7 +112,7 @@ def patched_env(env: dict[str, str], cython_line_tracing_requested: bool):
|
|
|
89
112
|
:yields: None
|
|
90
113
|
"""
|
|
91
114
|
orig_env = os.environ.copy()
|
|
92
|
-
expanded_env = {name: expandvars(var_val) for name, var_val in env.items()}
|
|
115
|
+
expanded_env = {name: expandvars(var_val) for name, var_val in env.items()} # type: ignore[no-untyped-call]
|
|
93
116
|
os.environ.update(expanded_env)
|
|
94
117
|
|
|
95
118
|
if cython_line_tracing_requested:
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
"""Data conversion helpers for the in-tree PEP 517 build backend."""
|
|
2
2
|
|
|
3
|
+
from collections.abc import Iterable, Iterator, Mapping
|
|
3
4
|
from itertools import chain
|
|
4
5
|
from re import sub as _substitute_with_regexp
|
|
6
|
+
from typing import Union
|
|
5
7
|
|
|
6
8
|
|
|
7
|
-
def _emit_opt_pairs(opt_pair):
|
|
9
|
+
def _emit_opt_pairs(opt_pair: tuple[str, Union[dict[str, str], str]]) -> Iterator[str]:
|
|
8
10
|
flag, flag_value = opt_pair
|
|
9
11
|
flag_opt = f"--{flag!s}"
|
|
10
12
|
if isinstance(flag_value, dict):
|
|
11
|
-
sub_pairs = flag_value.items()
|
|
13
|
+
sub_pairs: Iterable[tuple[str, ...]] = flag_value.items()
|
|
12
14
|
else:
|
|
13
15
|
sub_pairs = ((flag_value,),)
|
|
14
16
|
|
|
15
17
|
yield from ("=".join(map(str, (flag_opt,) + pair)) for pair in sub_pairs)
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
def get_cli_kwargs_from_config(
|
|
20
|
+
def get_cli_kwargs_from_config(
|
|
21
|
+
kwargs_map: dict[str, Union[str, dict[str, str]]],
|
|
22
|
+
) -> list[str]:
|
|
19
23
|
"""Make a list of options with values from config."""
|
|
20
24
|
return list(chain.from_iterable(map(_emit_opt_pairs, kwargs_map.items())))
|
|
21
25
|
|
|
22
26
|
|
|
23
|
-
def get_enabled_cli_flags_from_config(flags_map):
|
|
27
|
+
def get_enabled_cli_flags_from_config(flags_map: Mapping[str, bool]) -> list[str]:
|
|
24
28
|
"""Make a list of enabled boolean flags from config."""
|
|
25
29
|
return [f"--{flag}" for flag, is_enabled in flags_map.items() if is_enabled]
|
|
26
30
|
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
|
+
from collections.abc import Sequence
|
|
6
7
|
from itertools import chain
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
10
|
+
from Cython.Compiler.CmdLine import parse_command_line as _split_cython_cli_args
|
|
9
11
|
from Cython.Compiler.Main import compile as _translate_cython_cli_cmd
|
|
10
|
-
from Cython.Compiler.Main import parse_command_line as _split_cython_cli_args
|
|
11
12
|
|
|
12
13
|
from ._cython_configuration import get_local_cython_config as _get_local_cython_config
|
|
13
14
|
from ._cython_configuration import (
|
|
@@ -18,7 +19,7 @@ from ._cython_configuration import patched_env as _patched_cython_env
|
|
|
18
19
|
_PROJECT_PATH = Path(__file__).parents[2]
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
def run_main_program(argv) -> int | str:
|
|
22
|
+
def run_main_program(argv: Sequence[str]) -> int | str:
|
|
22
23
|
"""Invoke ``translate-cython`` or fail."""
|
|
23
24
|
if len(argv) != 2:
|
|
24
25
|
return 'This program only accepts one argument -- "translate-cython"'
|
|
@@ -38,12 +39,12 @@ def run_main_program(argv) -> int | str:
|
|
|
38
39
|
)
|
|
39
40
|
translate_cython_cli_args = _make_cythonize_cli_args_from_config(config)
|
|
40
41
|
|
|
41
|
-
cython_options, cython_sources = _split_cython_cli_args(
|
|
42
|
+
cython_options, cython_sources = _split_cython_cli_args( # type: ignore[no-untyped-call]
|
|
42
43
|
translate_cython_cli_args,
|
|
43
44
|
)
|
|
44
45
|
|
|
45
46
|
with _patched_cython_env(config['env'], cython_line_tracing_requested=True):
|
|
46
|
-
return _translate_cython_cli_cmd(
|
|
47
|
+
return _translate_cython_cli_cmd( # type: ignore[no-untyped-call,no-any-return]
|
|
47
48
|
cython_sources,
|
|
48
49
|
cython_options,
|
|
49
50
|
).num_errors
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from contextlib import suppress as _suppress
|
|
4
4
|
|
|
5
|
-
from setuptools.build_meta import * # Re-exporting PEP 517 hooks # pylint: disable=unused-wildcard-import,wildcard-import # noqa:
|
|
5
|
+
from setuptools.build_meta import * # Re-exporting PEP 517 hooks # pylint: disable=unused-wildcard-import,wildcard-import # noqa: F401, F403
|
|
6
6
|
|
|
7
7
|
# Re-exporting PEP 517 hooks
|
|
8
8
|
from ._backend import ( # type: ignore[assignment]
|
|
@@ -48,7 +48,6 @@ keep-going = false
|
|
|
48
48
|
# https://cython.rtfd.io/en/latest/src/userguide/source_files_and_compilation.html#compiler-directives
|
|
49
49
|
embedsignature = "True"
|
|
50
50
|
emit_code_comments = "True"
|
|
51
|
-
linetrace = "True" # Implies `profile=True`
|
|
52
51
|
|
|
53
52
|
[tool.local.cythonize.kwargs.compile-time-env]
|
|
54
53
|
# This section can contain compile time env vars
|
|
@@ -95,12 +94,3 @@ before-test = [] # Windows cmd has different syntax and pip chooses wheels
|
|
|
95
94
|
|
|
96
95
|
[tool.cibuildwheel.linux]
|
|
97
96
|
before-all = "yum install -y libffi-devel || apk add --upgrade libffi-dev || apt-get install libffi-dev"
|
|
98
|
-
|
|
99
|
-
# TODO: Remove this when there's a Cython 3.1 final release
|
|
100
|
-
# Remove PIP_CONSTRAINT from the environment
|
|
101
|
-
[[tool.cibuildwheel.overrides]]
|
|
102
|
-
select = "cp313t-*"
|
|
103
|
-
|
|
104
|
-
test-requires = "-r requirements/test-freethreading.txt"
|
|
105
|
-
inherit.environment = "append"
|
|
106
|
-
environment = {PIP_CONSTRAINT = "requirements/cython-freethreading.txt"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cython==3.1.2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pre-commit==4.2.0
|
|
@@ -19,8 +19,8 @@ if TYPE_CHECKING:
|
|
|
19
19
|
under_cached_property = under_cached_property_py
|
|
20
20
|
elif not NO_EXTENSIONS: # pragma: no branch
|
|
21
21
|
try:
|
|
22
|
-
from ._helpers_c import cached_property as cached_property_c # type: ignore[attr-defined, unused-ignore]
|
|
23
|
-
from ._helpers_c import under_cached_property as under_cached_property_c # type: ignore[attr-defined, unused-ignore]
|
|
22
|
+
from ._helpers_c import cached_property as cached_property_c # type: ignore[attr-defined, unused-ignore]
|
|
23
|
+
from ._helpers_c import under_cached_property as under_cached_property_c # type: ignore[attr-defined, unused-ignore]
|
|
24
24
|
|
|
25
25
|
cached_property = cached_property_c
|
|
26
26
|
under_cached_property = under_cached_property_c
|
|
@@ -37,6 +37,8 @@ cdef class under_cached_property:
|
|
|
37
37
|
def __set__(self, inst, value):
|
|
38
38
|
raise AttributeError("cached property is read-only")
|
|
39
39
|
|
|
40
|
+
__class_getitem__ = classmethod(GenericAlias)
|
|
41
|
+
|
|
40
42
|
|
|
41
43
|
cdef class cached_property:
|
|
42
44
|
"""Use as a class method decorator. It operates almost exactly like
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Various helper functions."""
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
|
+
from collections.abc import Mapping
|
|
4
5
|
from functools import cached_property
|
|
5
6
|
from typing import Any, Callable, Generic, Optional, Protocol, TypeVar, Union, overload
|
|
6
7
|
|
|
@@ -13,10 +14,13 @@ else:
|
|
|
13
14
|
Self = Any
|
|
14
15
|
|
|
15
16
|
_T = TypeVar("_T")
|
|
17
|
+
# We use Mapping to make it possible to use TypedDict, but this isn't
|
|
18
|
+
# technically type safe as we need to assign into the dict.
|
|
19
|
+
_Cache = TypeVar("_Cache", bound=Mapping[str, Any])
|
|
16
20
|
|
|
17
21
|
|
|
18
|
-
class
|
|
19
|
-
_cache:
|
|
22
|
+
class _CacheImpl(Protocol[_Cache]):
|
|
23
|
+
_cache: _Cache
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
class under_cached_property(Generic[_T]):
|
|
@@ -29,7 +33,7 @@ class under_cached_property(Generic[_T]):
|
|
|
29
33
|
variable. It is, in Python parlance, a data descriptor.
|
|
30
34
|
"""
|
|
31
35
|
|
|
32
|
-
def __init__(self, wrapped: Callable[
|
|
36
|
+
def __init__(self, wrapped: Callable[[Any], _T]) -> None:
|
|
33
37
|
self.wrapped = wrapped
|
|
34
38
|
self.__doc__ = wrapped.__doc__
|
|
35
39
|
self.name = wrapped.__name__
|
|
@@ -38,19 +42,19 @@ class under_cached_property(Generic[_T]):
|
|
|
38
42
|
def __get__(self, inst: None, owner: Optional[type[object]] = None) -> Self: ...
|
|
39
43
|
|
|
40
44
|
@overload
|
|
41
|
-
def __get__(self, inst:
|
|
45
|
+
def __get__(self, inst: _CacheImpl[Any], owner: Optional[type[object]] = None) -> _T: ... # type: ignore[misc]
|
|
42
46
|
|
|
43
47
|
def __get__(
|
|
44
|
-
self, inst: Optional[
|
|
48
|
+
self, inst: Optional[_CacheImpl[Any]], owner: Optional[type[object]] = None
|
|
45
49
|
) -> Union[_T, Self]:
|
|
46
50
|
if inst is None:
|
|
47
51
|
return self
|
|
48
52
|
try:
|
|
49
|
-
return inst._cache[self.name]
|
|
53
|
+
return inst._cache[self.name] # type: ignore[no-any-return]
|
|
50
54
|
except KeyError:
|
|
51
55
|
val = self.wrapped(inst)
|
|
52
56
|
inst._cache[self.name] = val
|
|
53
57
|
return val
|
|
54
58
|
|
|
55
|
-
def __set__(self, inst:
|
|
59
|
+
def __set__(self, inst: _CacheImpl[Any], value: _T) -> None:
|
|
56
60
|
raise AttributeError("cached property is read-only")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: propcache
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Accelerated property cache
|
|
5
5
|
Home-page: https://github.com/aio-libs/propcache
|
|
6
6
|
Author: Andrew Svetlov
|
|
@@ -35,6 +35,7 @@ Requires-Python: >=3.9
|
|
|
35
35
|
Description-Content-Type: text/x-rst
|
|
36
36
|
License-File: LICENSE
|
|
37
37
|
License-File: NOTICE
|
|
38
|
+
Dynamic: license-file
|
|
38
39
|
|
|
39
40
|
propcache
|
|
40
41
|
=========
|
|
@@ -151,6 +152,61 @@ Changelog
|
|
|
151
152
|
|
|
152
153
|
.. towncrier release notes start
|
|
153
154
|
|
|
155
|
+
0.3.2
|
|
156
|
+
=====
|
|
157
|
+
|
|
158
|
+
*(2025-06-09)*
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
Improved documentation
|
|
162
|
+
----------------------
|
|
163
|
+
|
|
164
|
+
- Fixed incorrect decorator usage in the ``~propcache.api.under_cached_property`` example code -- by `@meanmail <https://github.com/sponsors/meanmail>`__.
|
|
165
|
+
|
|
166
|
+
*Related issues and pull requests on GitHub:*
|
|
167
|
+
`#109 <https://github.com/aio-libs/propcache/issues/109>`__.
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
Packaging updates and notes for downstreams
|
|
171
|
+
-------------------------------------------
|
|
172
|
+
|
|
173
|
+
- Updated to use Cython 3.1 universally across the build path -- by `@lysnikolaou <https://github.com/sponsors/lysnikolaou>`__.
|
|
174
|
+
|
|
175
|
+
*Related issues and pull requests on GitHub:*
|
|
176
|
+
`#117 <https://github.com/aio-libs/propcache/issues/117>`__.
|
|
177
|
+
|
|
178
|
+
- Made Cython line tracing opt-in via the ``with-cython-tracing`` build config setting -- by `@bdraco <https://github.com/sponsors/bdraco>`__.
|
|
179
|
+
|
|
180
|
+
Previously, line tracing was enabled by default in ``pyproject.toml``, which caused build issues for some users and made wheels nearly twice as slow.
|
|
181
|
+
|
|
182
|
+
Now line tracing is only enabled when explicitly requested via ``pip install . --config-setting=with-cython-tracing=true`` or by setting the ``PROPCACHE_CYTHON_TRACING`` environment variable.
|
|
183
|
+
|
|
184
|
+
*Related issues and pull requests on GitHub:*
|
|
185
|
+
`#118 <https://github.com/aio-libs/propcache/issues/118>`__.
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
----
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
0.3.1
|
|
192
|
+
=====
|
|
193
|
+
|
|
194
|
+
*(2025-03-25)*
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
Bug fixes
|
|
198
|
+
---------
|
|
199
|
+
|
|
200
|
+
- Improved typing annotations, fixing some type errors under correct usage
|
|
201
|
+
and improving typing robustness generally -- by `@Dreamsorcerer <https://github.com/sponsors/Dreamsorcerer>`__.
|
|
202
|
+
|
|
203
|
+
*Related issues and pull requests on GitHub:*
|
|
204
|
+
`#103 <https://github.com/aio-libs/propcache/issues/103>`__.
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
----
|
|
208
|
+
|
|
209
|
+
|
|
154
210
|
0.3.0
|
|
155
211
|
=====
|
|
156
212
|
|
|
@@ -31,14 +31,11 @@ packaging/pep517_backend/_transformers.py
|
|
|
31
31
|
packaging/pep517_backend/cli.py
|
|
32
32
|
packaging/pep517_backend/hooks.py
|
|
33
33
|
requirements/codspeed.txt
|
|
34
|
-
requirements/cython-freethreading.txt
|
|
35
34
|
requirements/cython.txt
|
|
36
35
|
requirements/dev.txt
|
|
37
36
|
requirements/doc-spelling.txt
|
|
38
37
|
requirements/doc.txt
|
|
39
38
|
requirements/lint.txt
|
|
40
|
-
requirements/test-freethreading.txt
|
|
41
|
-
requirements/test-pure.txt
|
|
42
39
|
requirements/test.txt
|
|
43
40
|
requirements/towncrier.txt
|
|
44
41
|
src/propcache/__init__.py
|
|
@@ -53,7 +53,7 @@ class PropcacheImplementation:
|
|
|
53
53
|
)
|
|
54
54
|
def propcache_implementation(request: pytest.FixtureRequest) -> PropcacheImplementation:
|
|
55
55
|
"""Return a propcache variant facade."""
|
|
56
|
-
return request.param
|
|
56
|
+
return request.param # type: ignore[no-any-return]
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
@pytest.fixture(scope="session")
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from collections.abc import Callable
|
|
1
3
|
from operator import not_
|
|
2
|
-
from typing import Protocol
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Protocol, TypeVar
|
|
3
5
|
|
|
4
6
|
import pytest
|
|
5
7
|
|
|
6
8
|
from propcache.api import cached_property
|
|
7
9
|
|
|
10
|
+
if sys.version_info >= (3, 11):
|
|
11
|
+
from typing import assert_type
|
|
12
|
+
|
|
13
|
+
_T_co = TypeVar("_T_co", covariant=True)
|
|
8
14
|
|
|
9
|
-
class APIProtocol(Protocol):
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
class APIProtocol(Protocol):
|
|
17
|
+
def cached_property(
|
|
18
|
+
self, func: Callable[[Any], _T_co]
|
|
19
|
+
) -> cached_property[_T_co]: ...
|
|
12
20
|
|
|
13
21
|
|
|
14
22
|
def test_cached_property(propcache_module: APIProtocol) -> None:
|
|
@@ -21,23 +29,11 @@ def test_cached_property(propcache_module: APIProtocol) -> None:
|
|
|
21
29
|
return 1
|
|
22
30
|
|
|
23
31
|
a = A()
|
|
32
|
+
if sys.version_info >= (3, 11):
|
|
33
|
+
assert_type(a.prop, int)
|
|
24
34
|
assert a.prop == 1
|
|
25
35
|
|
|
26
36
|
|
|
27
|
-
def test_cached_property_class(propcache_module: APIProtocol) -> None:
|
|
28
|
-
class A:
|
|
29
|
-
def __init__(self) -> None:
|
|
30
|
-
"""Init."""
|
|
31
|
-
# self._cache not set because its never accessed in this test
|
|
32
|
-
|
|
33
|
-
@propcache_module.cached_property
|
|
34
|
-
def prop(self) -> None:
|
|
35
|
-
"""Docstring."""
|
|
36
|
-
|
|
37
|
-
assert isinstance(A.prop, propcache_module.cached_property)
|
|
38
|
-
assert A.prop.__doc__ == "Docstring."
|
|
39
|
-
|
|
40
|
-
|
|
41
37
|
def test_cached_property_without_cache(propcache_module: APIProtocol) -> None:
|
|
42
38
|
class A:
|
|
43
39
|
|
|
@@ -53,7 +49,7 @@ def test_cached_property_without_cache(propcache_module: APIProtocol) -> None:
|
|
|
53
49
|
a = A()
|
|
54
50
|
|
|
55
51
|
with pytest.raises(AttributeError):
|
|
56
|
-
a.prop = 123
|
|
52
|
+
a.prop = 123 # type: ignore[assignment]
|
|
57
53
|
|
|
58
54
|
|
|
59
55
|
def test_cached_property_check_without_cache(propcache_module: APIProtocol) -> None:
|
|
@@ -96,7 +92,10 @@ def test_cached_property_class_docstring(propcache_module: APIProtocol) -> None:
|
|
|
96
92
|
def prop(self) -> None:
|
|
97
93
|
"""Docstring."""
|
|
98
94
|
|
|
99
|
-
|
|
95
|
+
if TYPE_CHECKING:
|
|
96
|
+
assert isinstance(A.prop, cached_property)
|
|
97
|
+
else:
|
|
98
|
+
assert isinstance(A.prop, propcache_module.cached_property)
|
|
100
99
|
assert "Docstring." == A.prop.__doc__
|
|
101
100
|
|
|
102
101
|
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import sys
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Protocol, TypedDict, TypeVar
|
|
2
4
|
|
|
3
5
|
import pytest
|
|
4
6
|
|
|
5
7
|
from propcache.api import under_cached_property
|
|
6
8
|
|
|
9
|
+
if sys.version_info >= (3, 11):
|
|
10
|
+
from typing import assert_type
|
|
11
|
+
|
|
12
|
+
_T_co = TypeVar("_T_co", covariant=True)
|
|
7
13
|
|
|
8
|
-
class APIProtocol(Protocol):
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
class APIProtocol(Protocol):
|
|
16
|
+
def under_cached_property(
|
|
17
|
+
self, func: Callable[[Any], _T_co]
|
|
18
|
+
) -> under_cached_property[_T_co]: ...
|
|
11
19
|
|
|
12
20
|
|
|
13
21
|
def test_under_cached_property(propcache_module: APIProtocol) -> None:
|
|
@@ -19,21 +27,45 @@ def test_under_cached_property(propcache_module: APIProtocol) -> None:
|
|
|
19
27
|
def prop(self) -> int:
|
|
20
28
|
return 1
|
|
21
29
|
|
|
30
|
+
@propcache_module.under_cached_property
|
|
31
|
+
def prop2(self) -> str:
|
|
32
|
+
return "foo"
|
|
33
|
+
|
|
22
34
|
a = A()
|
|
35
|
+
if sys.version_info >= (3, 11):
|
|
36
|
+
assert_type(a.prop, int)
|
|
23
37
|
assert a.prop == 1
|
|
38
|
+
if sys.version_info >= (3, 11):
|
|
39
|
+
assert_type(a.prop2, str)
|
|
40
|
+
assert a.prop2 == "foo"
|
|
24
41
|
|
|
25
42
|
|
|
26
|
-
def
|
|
43
|
+
def test_under_cached_property_typeddict(propcache_module: APIProtocol) -> None:
|
|
44
|
+
"""Test static typing passes with TypedDict."""
|
|
45
|
+
|
|
46
|
+
class _Cache(TypedDict, total=False):
|
|
47
|
+
prop: int
|
|
48
|
+
prop2: str
|
|
49
|
+
|
|
27
50
|
class A:
|
|
28
51
|
def __init__(self) -> None:
|
|
29
|
-
|
|
52
|
+
self._cache: _Cache = {}
|
|
30
53
|
|
|
31
54
|
@propcache_module.under_cached_property
|
|
32
|
-
def prop(self) ->
|
|
33
|
-
|
|
55
|
+
def prop(self) -> int:
|
|
56
|
+
return 1
|
|
57
|
+
|
|
58
|
+
@propcache_module.under_cached_property
|
|
59
|
+
def prop2(self) -> str:
|
|
60
|
+
return "foo"
|
|
34
61
|
|
|
35
|
-
|
|
36
|
-
|
|
62
|
+
a = A()
|
|
63
|
+
if sys.version_info >= (3, 11):
|
|
64
|
+
assert_type(a.prop, int)
|
|
65
|
+
assert a.prop == 1
|
|
66
|
+
if sys.version_info >= (3, 11):
|
|
67
|
+
assert_type(a.prop2, str)
|
|
68
|
+
assert a.prop2 == "foo"
|
|
37
69
|
|
|
38
70
|
|
|
39
71
|
def test_under_cached_property_assignment(propcache_module: APIProtocol) -> None:
|
|
@@ -48,7 +80,7 @@ def test_under_cached_property_assignment(propcache_module: APIProtocol) -> None
|
|
|
48
80
|
a = A()
|
|
49
81
|
|
|
50
82
|
with pytest.raises(AttributeError):
|
|
51
|
-
a.prop = 123
|
|
83
|
+
a.prop = 123 # type: ignore[assignment]
|
|
52
84
|
|
|
53
85
|
|
|
54
86
|
def test_under_cached_property_without_cache(propcache_module: APIProtocol) -> None:
|
|
@@ -64,7 +96,7 @@ def test_under_cached_property_without_cache(propcache_module: APIProtocol) -> N
|
|
|
64
96
|
a = A()
|
|
65
97
|
|
|
66
98
|
with pytest.raises(AttributeError):
|
|
67
|
-
a.prop = 123
|
|
99
|
+
a.prop = 123 # type: ignore[assignment]
|
|
68
100
|
|
|
69
101
|
|
|
70
102
|
def test_under_cached_property_check_without_cache(
|
|
@@ -105,10 +137,16 @@ def test_under_cached_property_class_docstring(propcache_module: APIProtocol) ->
|
|
|
105
137
|
"""Init."""
|
|
106
138
|
|
|
107
139
|
@propcache_module.under_cached_property
|
|
108
|
-
def prop(self) ->
|
|
140
|
+
def prop(self) -> None:
|
|
109
141
|
"""Docstring."""
|
|
110
142
|
|
|
111
|
-
|
|
143
|
+
if TYPE_CHECKING:
|
|
144
|
+
# At type checking, the fixture doesn't represent the real module, so
|
|
145
|
+
# we use the global-level imported module to verify the isinstance() check here
|
|
146
|
+
# matches the behaviour users would see in real code.
|
|
147
|
+
assert isinstance(A.prop, under_cached_property)
|
|
148
|
+
else:
|
|
149
|
+
assert isinstance(A.prop, propcache_module.under_cached_property)
|
|
112
150
|
assert "Docstring." == A.prop.__doc__
|
|
113
151
|
|
|
114
152
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
cython==3.1.0a1
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
cython==3.0.12
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
pre-commit==4.1.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|