Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 68c9703

Browse files
committed
Merge branch 'release/3.9.0'
2 parents a895709 + 108c0f5 commit 68c9703

32 files changed

+1390
-364
lines changed

.coveragerc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ exclude_lines =
2626
@overload
2727
@types.overload
2828
@typing.overload
29+
types.Protocol

.github/workflows/main.yml

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,47 @@ jobs:
1111
timeout-minutes: 4
1212
strategy:
1313
matrix:
14-
python-version: ['3.8', '3.9', '3.10', '3.11']
14+
python-version: ['3.9', '3.10', '3.11', '3.12'] # Maybe soon?, '3.13']
1515

1616
steps:
17-
- uses: actions/checkout@v3
17+
- uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 1
1820
- name: Set up Python ${{ matrix.python-version }}
19-
uses: actions/setup-python@v3
21+
uses: actions/setup-python@v5
2022
with:
2123
python-version: ${{ matrix.python-version }}
2224
- name: Install dependencies
2325
run: |
24-
python -m pip install --upgrade pip setuptools flake8
26+
python -m pip install --upgrade pip setuptools ruff
2527
pip install -e '.[tests]'
2628
- name: Get versions
2729
run: |
2830
python -V
2931
pip freeze
30-
- name: flake8
31-
run: flake8 -v python_utils setup.py
32+
- name: ruff
33+
run: ruff check --output-format=github
3234
- name: pytest
3335
run: py.test
3436

3537
docs_and_lint:
3638
runs-on: ubuntu-latest
3739
timeout-minutes: 2
3840
steps:
39-
- uses: actions/checkout@v3
41+
- uses: actions/checkout@v4
4042
- name: Set up Python
41-
uses: actions/setup-python@v3
43+
uses: actions/setup-python@v5
4244
with:
4345
python-version: '3.10'
4446
- name: Install dependencies
4547
run: |
4648
python -m pip install --upgrade pip setuptools
47-
pip install -e '.[docs,tests]' pyright flake8 mypy
49+
pip install -e '.[docs,tests]' pyright ruff mypy
4850
- name: build docs
4951
run: make html
5052
working-directory: docs/
51-
- name: flake8
52-
run: flake8 -v python_utils setup.py
53+
- name: ruff
54+
run: ruff check --output-format=github
5355
- name: mypy
5456
run: mypy python_utils setup.py
5557
- name: pyright

.readthedocs.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Read the Docs configuration file for Sphinx projects
2+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3+
4+
# Required
5+
version: 2
6+
7+
# Set the OS, Python version and other tools you might need
8+
build:
9+
os: ubuntu-22.04
10+
tools:
11+
python: "3.12"
12+
# You can also specify other tool versions:
13+
# nodejs: "20"
14+
# rust: "1.70"
15+
# golang: "1.20"
16+
17+
# Build documentation in the "docs/" directory with Sphinx
18+
sphinx:
19+
configuration: docs/conf.py
20+
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
21+
# builder: "dirhtml"
22+
# Fail on all warnings to avoid broken references
23+
# fail_on_warning: true
24+
25+
# Optionally build your docs in additional formats such as PDF and ePub
26+
formats:
27+
- pdf
28+
- epub
29+
30+
# Optional but recommended, declare the Python requirements required
31+
# to build your documentation
32+
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
33+
python:
34+
install:
35+
- requirements: docs/requirements.txt

CONTRIBUTING.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,14 @@ Run tests
7474
$ py.test
7575
```
7676

77-
Note that this won't run `flake8` yet, so once all the tests succeed you can run `flake8` to check for code style errors.
77+
Note that this won't run `ruff` yet, so once all the tests succeed you can run `ruff check` to check for code style errors.
7878

7979
```bash
80-
$ flake8
80+
$ ruff check
81+
```
82+
83+
Lastly we test the types using `pyright`:
84+
85+
```bash
86+
$ pyright
8187
```

_python_utils_tests/test_aio.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,68 @@
1-
from datetime import datetime
2-
import pytest
31
import asyncio
42

3+
import pytest
54

65
from python_utils import types
7-
from python_utils.aio import acount, acontainer
6+
from python_utils.aio import acontainer, acount, adict
87

98

109
@pytest.mark.asyncio
11-
async def test_acount(monkeypatch: pytest.MonkeyPatch):
10+
async def test_acount(monkeypatch: pytest.MonkeyPatch) -> None:
1211
sleeps: types.List[float] = []
1312

14-
async def mock_sleep(delay: float):
13+
async def mock_sleep(delay: float) -> None:
1514
sleeps.append(delay)
1615

1716
monkeypatch.setattr(asyncio, 'sleep', mock_sleep)
1817

19-
async for i in acount(delay=1, stop=3.5):
20-
print('i', i, datetime.now())
18+
async for _i in acount(delay=1, stop=3.5):
19+
pass
2120

2221
assert len(sleeps) == 4
2322
assert sum(sleeps) == 4
2423

2524

2625
@pytest.mark.asyncio
27-
async def test_acontainer():
28-
async def async_gen():
26+
async def test_acontainer() -> None:
27+
async def async_gen() -> types.AsyncIterable[int]:
2928
yield 1
3029
yield 2
3130
yield 3
3231

33-
async def empty_gen():
32+
async def empty_gen() -> types.AsyncIterable[int]:
3433
if False:
3534
yield 1
3635

3736
assert await acontainer(async_gen) == [1, 2, 3]
3837
assert await acontainer(async_gen()) == [1, 2, 3]
3938
assert await acontainer(async_gen, set) == {1, 2, 3}
4039
assert await acontainer(async_gen(), set) == {1, 2, 3}
40+
assert await acontainer(async_gen, list) == [1, 2, 3]
41+
assert await acontainer(async_gen(), list) == [1, 2, 3]
42+
assert await acontainer(async_gen, tuple) == (1, 2, 3)
43+
assert await acontainer(async_gen(), tuple) == (1, 2, 3)
4144
assert await acontainer(empty_gen) == []
4245
assert await acontainer(empty_gen()) == []
46+
assert await acontainer(empty_gen, set) == set()
47+
assert await acontainer(empty_gen(), set) == set()
48+
assert await acontainer(empty_gen, list) == list()
49+
assert await acontainer(empty_gen(), list) == list()
50+
assert await acontainer(empty_gen, tuple) == tuple()
51+
assert await acontainer(empty_gen(), tuple) == tuple()
52+
53+
54+
@pytest.mark.asyncio
55+
async def test_adict() -> None:
56+
async def async_gen() -> types.AsyncIterable[types.Tuple[int, int]]:
57+
yield 1, 2
58+
yield 3, 4
59+
yield 5, 6
60+
61+
async def empty_gen() -> types.AsyncIterable[types.Tuple[int, int]]:
62+
if False:
63+
yield 1, 2
64+
65+
assert await adict(async_gen) == {1: 2, 3: 4, 5: 6}
66+
assert await adict(async_gen()) == {1: 2, 3: 4, 5: 6}
67+
assert await adict(empty_gen) == {}
68+
assert await adict(empty_gen()) == {}
Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import typing
12
from unittest.mock import MagicMock
23

34
import pytest
45

56
from python_utils.decorators import sample, wraps_classmethod
67

8+
T = typing.TypeVar('T')
9+
710

811
@pytest.fixture
912
def random(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
@@ -14,7 +17,7 @@ def random(monkeypatch: pytest.MonkeyPatch) -> MagicMock:
1417
return mock
1518

1619

17-
def test_sample_called(random: MagicMock):
20+
def test_sample_called(random: MagicMock) -> None:
1821
demo_function = MagicMock()
1922
decorated = sample(0.5)(demo_function)
2023
random.return_value = 0.4
@@ -28,7 +31,7 @@ def test_sample_called(random: MagicMock):
2831
assert demo_function.call_count == 3
2932

3033

31-
def test_sample_not_called(random: MagicMock):
34+
def test_sample_not_called(random: MagicMock) -> None:
3235
demo_function = MagicMock()
3336
decorated = sample(0.5)(demo_function)
3437
random.return_value = 0.5
@@ -40,31 +43,29 @@ def test_sample_not_called(random: MagicMock):
4043

4144
class SomeClass:
4245
@classmethod
43-
def some_classmethod(cls, arg): # type: ignore
44-
return arg # type: ignore
46+
def some_classmethod(cls, arg: T) -> T:
47+
return arg
4548

4649
@classmethod
4750
def some_annotated_classmethod(cls, arg: int) -> int:
4851
return arg
4952

5053

51-
def test_wraps_classmethod(): # type: ignore
54+
def test_wraps_classmethod() -> None:
5255
some_class = SomeClass()
53-
some_class.some_classmethod = MagicMock()
54-
wrapped_method = wraps_classmethod( # type: ignore
55-
SomeClass.some_classmethod # type: ignore
56-
)( # type: ignore
57-
some_class.some_classmethod # type: ignore
56+
some_class.some_classmethod = MagicMock() # type: ignore[method-assign]
57+
wrapped_method = wraps_classmethod(SomeClass.some_classmethod)(
58+
some_class.some_classmethod
5859
)
5960
wrapped_method(123)
60-
some_class.some_classmethod.assert_called_with(123) # type: ignore
61+
some_class.some_classmethod.assert_called_with(123)
6162

6263

63-
def test_wraps_annotated_classmethod(): # type: ignore
64+
def test_wraps_annotated_classmethod() -> None:
6465
some_class = SomeClass()
65-
some_class.some_annotated_classmethod = MagicMock()
66+
some_class.some_annotated_classmethod = MagicMock() # type: ignore[method-assign]
6667
wrapped_method = wraps_classmethod(SomeClass.some_annotated_classmethod)(
6768
some_class.some_annotated_classmethod
6869
)
69-
wrapped_method(123) # type: ignore
70+
wrapped_method(123)
7071
some_class.some_annotated_classmethod.assert_called_with(123)

_python_utils_tests/test_generators.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
@pytest.mark.asyncio
10-
async def test_abatcher():
10+
async def test_abatcher() -> None:
1111
async for batch in python_utils.abatcher(python_utils.acount(stop=9), 3):
1212
assert len(batch) == 3
1313

@@ -28,8 +28,8 @@ async def test_abatcher_timed() -> None:
2828

2929

3030
@pytest.mark.asyncio
31-
async def test_abatcher_timed_with_timeout():
32-
async def generator():
31+
async def test_abatcher_timed_with_timeout() -> None:
32+
async def generator() -> types.AsyncIterator[int]:
3333
# Test if the timeout is respected
3434
yield 0
3535
yield 1
@@ -57,12 +57,12 @@ async def generator():
5757
await batcher.__anext__()
5858

5959

60-
def test_batcher():
60+
def test_batcher() -> None:
6161
batch = []
6262
for batch in python_utils.batcher(range(9), 3):
6363
assert len(batch) == 3
6464

6565
for batch in python_utils.batcher(range(4), 3):
66-
pass
66+
assert batch is not None
6767

6868
assert len(batch) == 1

_python_utils_tests/test_import.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
from python_utils import import_, types
22

33

4-
def test_import_globals_relative_import():
4+
def test_import_globals_relative_import() -> None:
55
for i in range(-1, 5):
66
relative_import(i)
77

88

9-
def relative_import(level: int):
9+
def relative_import(level: int) -> None:
1010
locals_: types.Dict[str, types.Any] = {}
1111
globals_ = {'__name__': 'python_utils.import_'}
1212
import_.import_global('.formatters', locals_=locals_, globals_=globals_)
1313
assert 'camel_to_underscore' in globals_
1414

1515

16-
def test_import_globals_without_inspection():
17-
locals_ = {}
18-
globals_ = {'__name__': __name__}
16+
def test_import_globals_without_inspection() -> None:
17+
locals_: types.Dict[str, types.Any] = {}
18+
globals_: types.Dict[str, types.Any] = {'__name__': __name__}
1919
import_.import_global(
2020
'python_utils.formatters', locals_=locals_, globals_=globals_
2121
)
2222
assert 'camel_to_underscore' in globals_
2323

2424

25-
def test_import_globals_single_method():
26-
locals_ = {}
27-
globals_ = {'__name__': __name__}
25+
def test_import_globals_single_method() -> None:
26+
locals_: types.Dict[str, types.Any] = {}
27+
globals_: types.Dict[str, types.Any] = {'__name__': __name__}
2828
import_.import_global(
2929
'python_utils.formatters',
3030
['camel_to_underscore'],
@@ -34,19 +34,19 @@ def test_import_globals_single_method():
3434
assert 'camel_to_underscore' in globals_
3535

3636

37-
def test_import_globals_with_inspection():
37+
def test_import_globals_with_inspection() -> None:
3838
import_.import_global('python_utils.formatters')
3939
assert 'camel_to_underscore' in globals()
4040

4141

42-
def test_import_globals_missing_module():
42+
def test_import_globals_missing_module() -> None:
4343
import_.import_global(
4444
'python_utils.spam', exceptions=ImportError, locals_=locals()
4545
)
4646
assert 'camel_to_underscore' in globals()
4747

4848

49-
def test_import_locals_missing_module():
49+
def test_import_locals_missing_module() -> None:
5050
import_.import_global(
5151
'python_utils.spam', exceptions=ImportError, globals_=globals()
5252
)

_python_utils_tests/test_logger.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1+
# mypy: disable-error-code=misc
12
import pytest
23

34
from python_utils.loguru import Logurud
45

5-
66
loguru = pytest.importorskip('loguru')
77

88

9-
def test_logurud():
9+
def test_logurud() -> None:
1010
class MyClass(Logurud):
1111
pass
1212

_python_utils_tests/test_python_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from python_utils import __about__
22

33

4-
def test_definitions():
4+
def test_definitions() -> None:
55
# The setup.py requires this so we better make sure they exist :)
66
assert __about__.__version__
77
assert __about__.__author__

0 commit comments

Comments
 (0)