Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.11', '3.12', '3.13', '3.14']
python-version: ['3.11', '3.12', '3.13', '3.14', '3.15']

steps:
- uses: actions/checkout@v7.0.1
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ fabric.properties
### Custom ###
ex.py
experiments/
.vscode/tags
.vscode/
.pyre
.pytype
build/
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ Versions before `1.0.0` are `0Ver`-based:
incremental in minor, bugfixes only are patches.
See [0Ver](https://0ver.org/).

## 0.30.0 WIP

### Features

- Add `python3.15` support


## 0.29.1 WIP

Expand Down
4 changes: 2 additions & 2 deletions returns/contrib/mypy/_typeops/analtype.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from collections.abc import Sequence
from types import MappingProxyType
from typing import Final, Literal, overload

from mypy.checkmember import analyze_member_access
Expand All @@ -9,8 +8,9 @@

from returns.contrib.mypy._structures.args import FuncArg
from returns.contrib.mypy._structures.types import CallableContext
from returns.primitives.compat import make_immutable

_KIND_MAPPING: Final = MappingProxyType({
_KIND_MAPPING: Final = make_immutable({
# We have to replace `ARG_OPT` to `ARG_NAMED`,
# because `ARG_OPT` is only used in function defs, not calls.
# And `ARG_NAMED` is the same thing for calls.
Expand Down
4 changes: 2 additions & 2 deletions returns/contrib/mypy/_typeops/transform_callable.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from types import MappingProxyType
from typing import ClassVar, Final, final

from mypy.nodes import (
Expand All @@ -22,6 +21,7 @@
from mypy.types import Type as MypyType

from returns.contrib.mypy._structures.args import FuncArg
from returns.primitives.compat import make_immutable

_VARIADIC_KINDS: Final = frozenset((ARG_STAR, ARG_STAR2))
"""Kinds of arguments that consume leftover arguments.
Expand All @@ -33,7 +33,7 @@
_POSITIONAL_KINDS: Final = frozenset((ARG_POS, ARG_OPT))
"""Kinds of arguments that can be passed positionally."""

_KEYWORD_ONLY_KINDS: Final = MappingProxyType({
_KEYWORD_ONLY_KINDS: Final = make_immutable({
ARG_POS: ARG_NAMED,
ARG_OPT: ARG_NAMED_OPT,
})
Expand Down
33 changes: 14 additions & 19 deletions returns/contrib/pytest/plugin.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import inspect
import sys
from collections.abc import Callable, Generator, Iterator
from collections.abc import Callable, Generator, Iterator, Mapping
from contextlib import ExitStack, contextmanager
from functools import partial, wraps
from types import FrameType, MappingProxyType
from typing import (
TYPE_CHECKING,
Any,
Final,
TypeAlias,
TypeVar,
Union,
final,
)
from types import FrameType
from typing import TYPE_CHECKING, Any, TypeAlias, TypeVar, Union, final
from unittest import mock

import pytest
Expand Down Expand Up @@ -148,7 +140,7 @@ def _spy_error_handling() -> Generator[_ErrorsHandled]:
errs: _ErrorsHandled = {}
with ExitStack() as cleanup:
for container in _containers_to_patch():
for method, patch in _ERROR_HANDLING_PATCHERS.items():
for method, patch in _error_handling_patchers().items():
cleanup.enter_context(
mock.patch.object(
container,
Expand Down Expand Up @@ -182,6 +174,16 @@ def _containers_to_patch() -> list:
]


def _error_handling_patchers() -> Mapping[str, Callable]:
from returns.primitives.compat import make_immutable # noqa: PLC0415

return make_immutable({
'lash': _patched_error_handler,
'map': _patched_error_copier,
'alt': _patched_error_copier,
})


def _patched_error_handler(
original: _FunctionType,
errs: _ErrorsHandled,
Expand Down Expand Up @@ -224,10 +226,3 @@ def sync_wrapper(self, *args, **kwargs):
return original_result

return wraps(original)(sync_wrapper) # type: ignore


_ERROR_HANDLING_PATCHERS: Final = MappingProxyType({
'lash': _patched_error_handler,
'map': _patched_error_copier,
'alt': _patched_error_copier,
})
16 changes: 16 additions & 0 deletions returns/primitives/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import types
from collections.abc import Mapping
from typing import TypeVar

_KT = TypeVar('_KT')
_VT = TypeVar('_VT')


def make_immutable(
mutable_dict: Mapping[_KT, _VT],
) -> Mapping[_KT, _VT]:
"""Make a dictionary immutable."""
try: # pragma: >=3.15 cover
return frozendict(mutable_dict) # type: ignore[no-any-return, name-defined, unused-ignore]
except NameError: # pragma: <3.15 cover
return types.MappingProxyType(mutable_dict)
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ per-file-ignores =
# We allow `futures` to do attribute access:
returns/future.py: WPS402
returns/_internal/futures/*.py: WPS204, WPS433, WPS437
# Allow `types.MappingProxyType` in compat code:
returns/primitives/compat.py: WPS483
# We allow a lot of durty hacks in our plugins:
returns/contrib/mypy/*.py: S101, WPS201
returns/contrib/pytest/__init__.py: F401
Expand Down
Loading