Skip to content

Commit d61eb4e

Browse files
committed
Merge branch 'main' into ci/coverage
2 parents d1bebd3 + 9f05c1e commit d61eb4e

14 files changed

+247
-194
lines changed

.git-blame-ignore-revs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1f423a22d8b27926da7d7b7393c833da0f3714a4

.github/dependabot.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@ updates:
66
interval: "monthly"
77
labels:
88
- "type: Maintenance"
9+
groups:
10+
actions:
11+
patterns:
12+
- "*"
913
- package-ecosystem: "pip"
1014
directory: "/"
1115
schedule:
1216
interval: "monthly"
1317
labels:
1418
- "type: Maintenance"
19+
groups:
20+
actions:
21+
patterns:
22+
- "*"

.github/workflows/ci-tests.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
name: test
22

3-
on: [push, pull_request]
3+
on: [workflow_dispatch, push, pull_request]
4+
5+
concurrency:
6+
group: ${{ github.workflow }}-${{ github.ref }}
7+
cancel-in-progress: true
48

59
jobs:
610
default:
@@ -9,7 +13,7 @@ jobs:
913
matrix:
1014
os: [ubuntu, macos, windows]
1115
python-version:
12-
["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.8", "pypy-3.9"]
16+
["3.9", "3.10", "3.11", "3.12", "3.13", "pypy-3.9", "pypy-3.10"]
1317

1418
steps:
1519
- uses: actions/checkout@v4

.github/workflows/label-check.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ on:
44
pull_request:
55
types:
66
- opened
7+
- reopened
78
- labeled
89
- unlabeled
10+
- synchronize
911

1012
env:
1113
LABELS: ${{ join( github.event.pull_request.labels.*.name, ' ' ) }}

.github/workflows/lint.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.

.github/workflows/milestone-merged-prs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
name: attach to PR
1313
runs-on: ubuntu-latest
1414
steps:
15-
- uses: scientific-python/attach-next-milestone-action@bc07be829f693829263e57d5e8489f4e57d3d420
15+
- uses: scientific-python/attach-next-milestone-action@c9cfab10ad0c67fed91b01103db26b7f16634639
1616
with:
1717
token: ${{ secrets.MILESTONE_LABELER_TOKEN }}
1818
force: true

.pre-commit-config.yaml

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
# Install pre-commit hooks via
22
# pre-commit install
33

4+
ci:
5+
autofix_prs: false
6+
autofix_commit_msg: |
7+
'[pre-commit.ci 🤖] Apply code format tools to PR'
8+
autoupdate_schedule: quarterly
9+
410
repos:
511
- repo: https://github.com/pre-commit/pre-commit-hooks
6-
rev: c4a0b883114b00d8d76b479c820ce7950211c99b # frozen: v4.5.0
12+
rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0
713
hooks:
814
- id: trailing-whitespace
915
- id: end-of-file-fixer
@@ -16,20 +22,21 @@ repos:
1622
- id: check-toml
1723
- id: check-added-large-files
1824

19-
- repo: https://github.com/pre-commit/mirrors-prettier
20-
rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0
25+
- repo: https://github.com/rbubley/mirrors-prettier
26+
rev: bc7af46104f0f5368b95878decf720f9f00c2559 # frozen: v3.4.2
2127
hooks:
2228
- id: prettier
2329
files: \.(html|md|yml|yaml|toml)
2430
args: [--prose-wrap=preserve]
2531

26-
- repo: https://github.com/psf/black
27-
rev: 552baf822992936134cbd31a38f69c8cfe7c0f05 # frozen: 24.3.0
28-
hooks:
29-
- id: black
30-
3132
- repo: https://github.com/astral-sh/ruff-pre-commit
32-
rev: 0ccbb5b7942d83fbcf7cb5e0fd99633efd2351d7 # frozen: v0.3.5
33+
rev: 89c421dff2e1026ba12cdb9ebd731f4a83aa8021 # frozen: v0.8.6
3334
hooks:
3435
- id: ruff
35-
args: [--fix, --exit-non-zero-on-fix]
36+
args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"]
37+
- id: ruff-format
38+
39+
- repo: https://github.com/codespell-project/codespell
40+
rev: "193cd7d27cd571f79358af09a8fb8997e54f8fff" # frozen: v2.3.0
41+
hooks:
42+
- id: codespell

CHANGELOG.md

Lines changed: 97 additions & 97 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
[![PyPI](https://img.shields.io/pypi/v/lazy_loader)](https://pypi.org/project/lazy_loader/)
2-
[![Test status](https://github.com/scientific-python/lazy_loader/workflows/test/badge.svg?branch=main)](https://github.com/scientific-python/lazy_loader/actions?query=workflow%3A%22test%22)
3-
[![Test coverage](https://codecov.io/gh/scientific-python/lazy_loader/branch/main/graph/badge.svg)](https://app.codecov.io/gh/scientific-python/lazy_loader/branch/main)
1+
[![PyPI](https://img.shields.io/pypi/v/lazy-loader)](https://pypi.org/project/lazy-loader/)
2+
[![Test status](https://github.com/scientific-python/lazy-loader/workflows/test/badge.svg?branch=main)](https://github.com/scientific-python/lazy-loader/actions?query=workflow%3A%22test%22)
3+
[![Test coverage](https://codecov.io/gh/scientific-python/lazy-loader/branch/main/graph/badge.svg)](https://app.codecov.io/gh/scientific-python/lazy-loader/branch/main)
44

5-
`lazy_loader` makes it easy to load subpackages and functions on demand.
5+
`lazy-loader` makes it easy to load subpackages and functions on demand.
66

77
## Motivation
88

@@ -14,10 +14,10 @@ For a more detailed discussion, see [the SPEC](https://scientific-python.org/spe
1414
## Installation
1515

1616
```
17-
pip install -U lazy_loader
17+
pip install -U lazy-loader
1818
```
1919

20-
We recommend using `lazy_loader` with Python >= 3.11.
20+
We recommend using `lazy-loader` with Python >= 3.11.
2121
If using Python 3.11, please upgrade to 3.11.9 or later.
2222
If using Python 3.12, please upgrade to 3.12.3 or later.
2323
These versions [avoid](https://github.com/python/cpython/pull/114781) a [known race condition](https://github.com/python/cpython/issues/114763).

RELEASE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Release process for `lazy_loader`
1+
# Release process for `lazy-loader`
22

33
## Introduction
44

@@ -17,7 +17,7 @@ Example `version number`
1717
export VERSION=<version number>
1818
export PREVIOUS=<previous version number>
1919
export ORG="scientific-python"
20-
export REPO="lazy_loader"
20+
export REPO="lazy-loader"
2121
export LOG="CHANGELOG.md"
2222

2323
- Autogenerate release notes
@@ -46,17 +46,17 @@ Example `version number`
4646

4747
git push --tags origin main
4848

49-
where `origin` is the name of the `github.com:scientific-python/lazy_loader`
49+
where `origin` is the name of the `github.com:scientific-python/lazy-loader`
5050
repository
5151

5252
- Create release from tag
5353

54-
- go to https://github.com/scientific-python/lazy_loader/releases/new?tag=v${VERSION}
54+
- go to https://github.com/scientific-python/lazy-loader/releases/new?tag=v${VERSION}
5555
- add v${VERSION} for the `Release title`
5656
- paste contents (or upload) of ${VERSION}.md in the `Describe this release section`
5757
- if pre-release check the box labelled `Set as a pre-release`
5858

59-
- Update https://github.com/scientific-python/lazy_loader/milestones:
59+
- Update https://github.com/scientific-python/lazy-loader/milestones:
6060

6161
- close old milestone
6262
- ensure new milestone exists (perhaps setting due date)

lazy_loader/__init__.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import warnings
1616

1717
__version__ = "0.5rc0.dev0"
18-
__all__ = ["attach", "load", "attach_stub"]
18+
__all__ = ["attach", "attach_stub", "load"]
1919

2020

2121
threadlock = threading.Lock()
@@ -38,9 +38,7 @@ def attach(package_name, submodules=None, submod_attrs=None):
3838
The typical way to call this function, replacing the above imports, is::
3939
4040
__getattr__, __dir__, __all__ = lazy.attach(
41-
__name__,
42-
['mysubmodule', 'anothersubmodule'],
43-
{'foo': ['someattr']}
41+
__name__, ["mysubmodule", "anothersubmodule"], {"foo": ["someattr"]}
4442
)
4543
4644
Parameters
@@ -92,13 +90,13 @@ def __getattr__(name):
9290
raise AttributeError(f"No {package_name} attribute {name}")
9391

9492
def __dir__():
95-
return __all__
93+
return __all__.copy()
9694

9795
if os.environ.get("EAGER_IMPORT", ""):
9896
for attr in set(attr_to_modules.keys()) | submodules:
9997
__getattr__(attr)
10098

101-
return __getattr__, __dir__, list(__all__)
99+
return __getattr__, __dir__, __all__.copy()
102100

103101

104102
class DelayedImportErrorModule(types.ModuleType):
@@ -114,13 +112,13 @@ def __getattr__(self, x):
114112
fd = self.__frame_data
115113
raise ModuleNotFoundError(
116114
f"{self.__message}\n\n"
117-
"This error is lazily reported, having originally occured in\n"
115+
"This error is lazily reported, having originally occurred in\n"
118116
f' File {fd["filename"]}, line {fd["lineno"]}, in {fd["function"]}\n\n'
119117
f'----> {"".join(fd["code_context"] or "").strip()}'
120118
)
121119

122120

123-
def load(fullname, *, require=None, error_on_import=False):
121+
def load(fullname, *, require=None, error_on_import=False, suppress_warning=False):
124122
"""Return a lazily imported proxy for a module.
125123
126124
We often see the following pattern::
@@ -162,7 +160,7 @@ def myfunc():
162160
fullname : str
163161
The full name of the module or submodule to import. For example::
164162
165-
sp = lazy.load('scipy') # import scipy as sp
163+
sp = lazy.load("scipy") # import scipy as sp
166164
167165
require : str
168166
A dependency requirement as defined in PEP-508. For example::
@@ -176,6 +174,10 @@ def myfunc():
176174
Whether to postpone raising import errors until the module is accessed.
177175
If set to `True`, import errors are raised as soon as `load` is called.
178176
177+
suppress_warning : bool
178+
Whether to prevent emitting a warning when loading subpackages.
179+
If set to `True`, no warning will occur.
180+
179181
Returns
180182
-------
181183
pm : importlib.util._LazyModule
@@ -191,10 +193,10 @@ def myfunc():
191193
if have_module and require is None:
192194
return module
193195

194-
if "." in fullname:
196+
if not suppress_warning and "." in fullname:
195197
msg = (
196198
"subpackages can technically be lazily loaded, but it causes the "
197-
"package to be eagerly loaded even if it is already lazily loaded."
199+
"package to be eagerly loaded even if it is already lazily loaded. "
198200
"So, you probably shouldn't use subpackages with this lazy feature."
199201
)
200202
warnings.warn(msg, RuntimeWarning)
@@ -224,21 +226,19 @@ def myfunc():
224226
raise ModuleNotFoundError(not_found_message)
225227
import inspect
226228

227-
try:
228-
parent = inspect.stack()[1]
229-
frame_data = {
230-
"filename": parent.filename,
231-
"lineno": parent.lineno,
232-
"function": parent.function,
233-
"code_context": parent.code_context,
234-
}
235-
return DelayedImportErrorModule(
236-
frame_data,
237-
"DelayedImportErrorModule",
238-
message=not_found_message,
239-
)
240-
finally:
241-
del parent
229+
parent = inspect.stack()[1]
230+
frame_data = {
231+
"filename": parent.filename,
232+
"lineno": parent.lineno,
233+
"function": parent.function,
234+
"code_context": parent.code_context,
235+
}
236+
del parent
237+
return DelayedImportErrorModule(
238+
frame_data,
239+
"DelayedImportErrorModule",
240+
message=not_found_message,
241+
)
242242

243243
if spec is not None:
244244
module = importlib.util.module_from_spec(spec)
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
def some_func():
22
"""Function with same name as submodule."""
3-
pass

lazy_loader/tests/test_lazy_loader.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_lazy_import_subpackages():
3535
with pytest.warns(RuntimeWarning):
3636
hp = lazy.load("html.parser")
3737
assert "html" in sys.modules
38-
assert type(sys.modules["html"]) == type(pytest)
38+
assert type(sys.modules["html"]) is type(pytest)
3939
assert isinstance(hp, importlib.util._LazyModule)
4040
assert "html.parser" in sys.modules
4141
assert sys.modules["html.parser"] == hp
@@ -104,6 +104,29 @@ def test_lazy_attach():
104104
assert locls[k] == v
105105

106106

107+
def test_lazy_attach_returns_copies():
108+
_get, _dir, _all = lazy.attach(
109+
__name__, ["my_submodule", "another_submodule"], {"foo": ["some_attr"]}
110+
)
111+
assert _dir() is not _dir()
112+
assert _dir() == _all
113+
assert _dir() is not _all
114+
115+
expected = ["another_submodule", "my_submodule", "some_attr"]
116+
assert _dir() == expected
117+
assert _all == expected
118+
assert _dir() is not _all
119+
120+
_dir().append("modify_returned_list")
121+
assert _dir() == expected
122+
assert _all == expected
123+
assert _dir() is not _all
124+
125+
_all.append("modify_returned_all")
126+
assert _dir() == expected
127+
assert _all == [*expected, "modify_returned_all"]
128+
129+
107130
def test_attach_same_module_and_attr_name():
108131
from lazy_loader.tests import fake_pkg
109132

@@ -186,5 +209,6 @@ def test_parallel_load():
186209
[
187210
sys.executable,
188211
os.path.join(os.path.dirname(__file__), "import_np_parallel.py"),
189-
]
212+
],
213+
check=True,
190214
)

0 commit comments

Comments
 (0)