├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── Bug.md │ └── config.yml ├── dependabot.yml ├── pull_request_template.md ├── workflows │ └── test.yml └── zizmor.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── Makefile ├── _static │ └── overrides.css ├── conf.py ├── index.rst └── pages │ ├── changelog.rst │ ├── container.rst │ ├── context.rst │ ├── contrib │ ├── hypothesis_plugins.rst │ ├── mypy_plugins.rst │ └── pytest_plugins.rst │ ├── converters.rst │ ├── create-your-own-container.rst │ ├── curry.rst │ ├── development.rst │ ├── do-notation.rst │ ├── functions.rst │ ├── future.rst │ ├── hkt.rst │ ├── interfaces.rst │ ├── io.rst │ ├── maybe.rst │ ├── methods.rst │ ├── pipeline.rst │ ├── pointfree.rst │ ├── quickstart.rst │ ├── railway.rst │ ├── result.rst │ ├── trampolines.rst │ └── types.rst ├── poetry.lock ├── pyproject.toml ├── returns ├── __init__.py ├── _internal │ ├── __init__.py │ ├── futures │ │ ├── __init__.py │ │ ├── _future.py │ │ ├── _future_result.py │ │ └── _reader_future_result.py │ └── pipeline │ │ ├── __init__.py │ │ ├── flow.py │ │ ├── managed.py │ │ ├── pipe.py │ │ └── pipe.pyi ├── context │ ├── __init__.py │ ├── requires_context.py │ ├── requires_context_future_result.py │ ├── requires_context_ioresult.py │ └── requires_context_result.py ├── contrib │ ├── __init__.py │ ├── hypothesis │ │ ├── __init__.py │ │ ├── _entrypoint.py │ │ ├── containers.py │ │ ├── laws.py │ │ └── type_resolver.py │ ├── mypy │ │ ├── __init__.py │ │ ├── _consts.py │ │ ├── _features │ │ │ ├── __init__.py │ │ │ ├── curry.py │ │ │ ├── do_notation.py │ │ │ ├── flow.py │ │ │ ├── kind.py │ │ │ ├── partial.py │ │ │ └── pipe.py │ │ ├── _structures │ │ │ ├── __init__.py │ │ │ ├── args.py │ │ │ └── types.py │ │ ├── _typeops │ │ │ ├── __init__.py │ │ │ ├── analtype.py │ │ │ ├── fallback.py │ │ │ ├── inference.py │ │ │ ├── transform_callable.py │ │ │ └── visitor.py │ │ └── returns_plugin.py │ └── pytest │ │ ├── __init__.py │ │ └── plugin.py ├── converters.py ├── curry.py ├── functions.py ├── future.py ├── interfaces │ ├── __init__.py │ ├── altable.py │ ├── applicative.py │ ├── bimappable.py │ ├── bindable.py │ ├── container.py │ ├── equable.py │ ├── failable.py │ ├── lashable.py │ ├── mappable.py │ ├── specific │ │ ├── __init__.py │ │ ├── future.py │ │ ├── future_result.py │ │ ├── io.py │ │ ├── ioresult.py │ │ ├── maybe.py │ │ ├── reader.py │ │ ├── reader_future_result.py │ │ ├── reader_ioresult.py │ │ ├── reader_result.py │ │ └── result.py │ ├── swappable.py │ └── unwrappable.py ├── io.py ├── iterables.py ├── maybe.py ├── methods │ ├── __init__.py │ ├── cond.py │ ├── partition.py │ └── unwrap_or_failure.py ├── pipeline.py ├── pointfree │ ├── __init__.py │ ├── alt.py │ ├── apply.py │ ├── bimap.py │ ├── bind.py │ ├── bind_async.py │ ├── bind_async_context_future_result.py │ ├── bind_async_future.py │ ├── bind_async_future_result.py │ ├── bind_awaitable.py │ ├── bind_context.py │ ├── bind_context_future_result.py │ ├── bind_context_ioresult.py │ ├── bind_context_result.py │ ├── bind_future.py │ ├── bind_future_result.py │ ├── bind_io.py │ ├── bind_ioresult.py │ ├── bind_optional.py │ ├── bind_result.py │ ├── compose_result.py │ ├── cond.py │ ├── lash.py │ ├── map.py │ ├── modify_env.py │ └── unify.py ├── primitives │ ├── __init__.py │ ├── asserts.py │ ├── container.py │ ├── exceptions.py │ ├── hkt.py │ ├── laws.py │ ├── reawaitable.py │ ├── tracing.py │ └── types.py ├── py.typed ├── result.py ├── trampolines.py └── unsafe.py ├── setup.cfg ├── tests ├── test_context │ ├── test_requires_context │ │ ├── test_context.py │ │ ├── test_context_equality.py │ │ └── test_context_utils.py │ ├── test_requires_context_ioresult │ │ ├── test_context_ioresult.py │ │ ├── test_requires_context_ioresult.py │ │ ├── test_requires_context_ioresult_bind.py │ │ └── test_requires_context_ioresult_cast.py │ └── test_requires_context_result │ │ ├── test_context_result.py │ │ ├── test_requires_context_result_bind.py │ │ └── test_requires_context_result_cast.py ├── test_contrib │ ├── test_hypothesis │ │ ├── __init__.py │ │ ├── test_laws │ │ │ ├── test_custom_interface_with_laws.py │ │ │ ├── test_custom_strategy_for_callable.py │ │ │ ├── test_custom_type_applicative.py │ │ │ ├── test_custom_type_with_init.py │ │ │ ├── test_unsatisfiable_type.py │ │ │ ├── test_user_specified_strategy.py │ │ │ └── test_wrong_custom_type_with_init.py │ │ ├── test_type_resolution.py │ │ └── test_type_resolver.py │ └── test_pytest │ │ ├── test_plugin_error_handler.py │ │ └── test_plugin_has_trace.py ├── test_converters │ └── test_flatten.py ├── test_curry │ └── test_curry.py ├── test_examples │ ├── test_context │ │ └── test_reader_future_result.py │ ├── test_future │ │ └── test_future_result.py │ ├── test_io │ │ └── test_ioresult_container │ │ │ └── test_ioresult_pattern_matching.py │ ├── test_maybe │ │ └── test_maybe_pattern_matching.py │ ├── test_result │ │ └── test_result_pattern_matching.py │ └── test_your_container │ │ ├── test_pair1.py │ │ ├── test_pair2.py │ │ ├── test_pair3.py │ │ └── test_pair4.py ├── test_functions │ ├── test_compose.py │ └── test_raise_exception.py ├── test_future │ ├── test_future_container │ │ ├── test_asyncize_decorator.py │ │ ├── test_future_decorator.py │ │ ├── test_future_equality.py │ │ └── test_future_units.py │ └── test_future_result │ │ ├── test_future_result_decorator.py │ │ ├── test_future_result_equality.py │ │ └── test_future_result_units.py ├── test_io │ ├── test_io_container │ │ ├── test_io.py │ │ ├── test_io_equality.py │ │ ├── test_io_functions │ │ │ └── test_impure.py │ │ └── test_io_pickle.py │ └── test_ioresult_container │ │ ├── test_ioresult_bind.py │ │ ├── test_ioresult_equals.py │ │ ├── test_ioresult_functions │ │ └── test_impure_safe.py │ │ ├── test_ioresult_map.py │ │ ├── test_ioresult_values.py │ │ └── test_ioresulte_cast.py ├── test_iterables │ └── test_fold │ │ ├── test_collect.py │ │ ├── test_collect_all.py │ │ └── test_loop.py ├── test_laws.py ├── test_maybe │ ├── test_maybe_bind.py │ ├── test_maybe_equality.py │ ├── test_maybe_functions │ │ └── test_maybe_decorator.py │ ├── test_maybe_unwrap.py │ └── test_nothing_singleton.py ├── test_methods │ └── test_partition.py ├── test_pattern_matching.py ├── test_pipeline │ ├── test_is_successful.py │ └── test_managed │ │ ├── test_managed_future_result.py │ │ ├── test_managed_ioresult.py │ │ ├── test_managed_reader_future_result.py │ │ └── test_managed_reader_ioresult.py ├── test_primitives │ ├── test_asserts │ │ └── test_assert_equal.py │ ├── test_container │ │ └── test_base_container │ │ │ ├── test_pickle.py │ │ │ └── test_pickle_backward_deserialization.py │ ├── test_exceptions │ │ └── test_pickle_unwrap_failed_error.py │ └── test_laws │ │ └── test_lawful │ │ └── test_laws_resolution.py ├── test_result │ ├── test_result_bind.py │ ├── test_result_equality.py │ ├── test_result_error.py │ ├── test_result_failure.py │ ├── test_result_functions │ │ └── test_safe.py │ ├── test_result_map.py │ ├── test_result_unwrap.py │ └── test_result_value_or.py ├── test_trampolines │ └── test_trampoline_decorator.py └── test_unsafe │ └── test_unsafe_perform_io.py └── typesafety ├── test_context ├── test_requires_context │ ├── test_context.yml │ ├── test_requires_context_cast.yml │ ├── test_requires_context_type.yml │ └── test_requires_context_typecast.yml ├── test_requires_context_future_result │ ├── test_context_future_result.yml │ ├── test_requires_context_future_result.yml │ ├── test_requires_context_future_result_aliases.yml │ ├── test_requires_context_future_result_cast.yml │ └── test_requires_context_future_result_unit.yml ├── test_requires_context_ioresult │ ├── test_context_ioresult.yml │ ├── test_requires_context_ioresult.yml │ ├── test_requires_context_ioresult_aliases.yml │ ├── test_requires_context_ioresult_cast.yml │ └── test_requires_context_ioresult_unit.yml └── test_requires_context_result │ ├── test_context_result.yml │ ├── test_requires_context_cast.yml │ ├── test_requires_context_result.yml │ └── test_requires_context_result_unit.yml ├── test_contrib └── test_hypothesis │ └── test_laws │ └── test_check_all_laws.yml ├── test_converters ├── test_flatten.yml ├── test_maybe_to_result.yml └── test_result_to_maybe.yml ├── test_curry ├── test_curry │ ├── test_curry.yml │ ├── test_curry_args_kwargs.yml │ ├── test_curry_arguments.yml │ └── test_curry_generics.yml └── test_partial │ ├── test_partial.yml │ ├── test_partial_arguments.yml │ ├── test_partial_generic.yml │ └── test_partial_overload.yml ├── test_examples └── test_your_container │ ├── test_pair4_def.yml │ ├── test_pair4_error.yml │ └── test_pair4_reuse.yml ├── test_functions ├── test_compose.yml ├── test_identity.yml ├── test_not_.yml ├── test_raise_exception.yml └── test_tap.yml ├── test_future ├── test_future_container │ ├── test_asyncify_decorator.yml │ ├── test_do.yml │ ├── test_future_base.yml │ ├── test_future_decorator.yml │ └── test_future_typecast.yml └── test_future_result_container │ ├── test_do.yml │ ├── test_future_result_base.yml │ ├── test_future_result_typecast.yml │ └── test_future_safe_decorator.yml ├── test_interfaces ├── test_altable │ └── test_inheritance.yml ├── test_applicative │ └── test_inheritance.yml ├── test_bimappable │ └── test_bimappable_inheritance.yml ├── test_bindable │ └── test_inheritance.yml ├── test_container │ └── test_inheritance.yml ├── test_equality │ └── test_inheritance.yml ├── test_failable │ ├── test_diverse_failable.yml │ ├── test_failable.yml │ └── test_single_failable.yml ├── test_lashable │ └── test_inheritance.yml ├── test_mappable │ └── test_inheritance.yml ├── test_specific │ ├── test_future │ │ ├── test_futurebased_inheritance.yml │ │ └── test_futurelike_inheritance.yml │ ├── test_future_result │ │ ├── test_future_result_based.yml │ │ └── test_future_result_like.yml │ ├── test_io │ │ ├── test_io_based.yml │ │ └── test_io_like.yml │ ├── test_ioresult │ │ ├── test_ioresultbased_inheritance.yml │ │ └── test_ioresultlike_inheritance.yml │ ├── test_maybe │ │ ├── test_maybe_based.yml │ │ └── test_maybe_like.yml │ ├── test_reader │ │ ├── test_reader_based2.yml │ │ ├── test_reader_like2.yml │ │ └── test_reader_like3.yml │ ├── test_reader_future_result │ │ ├── test_reader_future_result_based.yml │ │ └── test_reader_future_result_like.yml │ ├── test_reader_ioresult │ │ ├── test_reader_ioresult_based.yml │ │ └── test_reader_ioresult_like.yml │ ├── test_reader_result │ │ ├── test_reader_result_based.yml │ │ └── test_reader_result_like.yml │ └── test_result │ │ ├── test_resultbased_inheritance.yml │ │ └── test_resultlike_inheritance.yml ├── test_swappable │ └── test_inheritance.yml └── test_unwrappable │ └── test_inheritance.yml ├── test_io ├── test_io_container │ ├── test_do.yml │ ├── test_impure.yml │ ├── test_io_base.yml │ └── test_io_type_cast.yml └── test_ioresult_container │ ├── test_construct_iofailure.yml │ ├── test_construct_iosucess.yml │ ├── test_do.yml │ ├── test_impure_safe.yml │ ├── test_ioresult_helpers.yml │ └── test_ioresult_typecast.yml ├── test_iterables └── test_fold │ ├── test_fold_collect.yml │ ├── test_fold_collect_all.yml │ └── test_fold_loop.yml ├── test_maybe ├── test_do.yml ├── test_maybe_decorator.yml ├── test_maybe_type.yml └── test_maybe_type_cast.yml ├── test_methods ├── test_cond.yml ├── test_partition.yml └── test_unwrap_or_failure.yml ├── test_pipeline ├── test_flow │ ├── test_flow_args.yml │ ├── test_flow_base.yml │ ├── test_flow_curry.yml │ ├── test_flow_errors.yml │ └── test_flow_generics.yml ├── test_is_successful.yml ├── test_managed │ ├── test_managed_errors.yml │ └── test_managed_types.yml └── test_pipe │ ├── test_pipe_base.yml │ ├── test_pipe_callable_protocol.yml │ ├── test_pipe_curry.yml │ ├── test_pipe_errors.yml │ └── test_pipe_generic.yml ├── test_pointfree ├── test_alt.yml ├── test_apply.yml ├── test_bimap.yml ├── test_bind.yml ├── test_bind_async.yml ├── test_bind_async_context_future_result.yml ├── test_bind_async_future.yml ├── test_bind_async_future_result.yml ├── test_bind_awaitable.yml ├── test_bind_context2.yml ├── test_bind_context3.yml ├── test_bind_context_future_result.yml ├── test_bind_context_ioresult.yml ├── test_bind_context_result.yml ├── test_bind_future.yml ├── test_bind_future_result.yml ├── test_bind_io.yml ├── test_bind_ioresult.yml ├── test_bind_optional.yml ├── test_bind_result.yml ├── test_compose_result.yml ├── test_cond.yml ├── test_map.yml ├── test_modify_env2.yml ├── test_modify_env3.yml ├── test_rescue.yml └── test_unify.yml ├── test_primitives ├── test_hkt │ ├── test_dekind │ │ └── test_dekind.yml │ ├── test_kinded │ │ ├── test_kinded.yml │ │ ├── test_kinded_methods.yml │ │ ├── test_kinded_nested.yml │ │ └── test_kinded_overload.yml │ ├── test_kindn │ │ ├── test_kindn.yml │ │ └── test_kindn_getattr.yml │ └── test_supports_kind.yml ├── test_reawaitable │ └── test_reawaitable_decorator.yml └── test_tracing │ └── test_collect_traces.yml ├── test_result ├── test_attempt.yml ├── test_construct_failure.yml ├── test_construct_success.yml ├── test_do.yml ├── test_result_error.yml ├── test_result_type_cast.yml └── test_safe.yml ├── test_trampolines └── test_trampoline.yml └── test_unsafe └── test_unsafe.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # Check http://editorconfig.org for more information 2 | # This is the main config file for this project: 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | indent_style = space 10 | insert_final_newline = true 11 | indent_size = 2 12 | 13 | [*.py] 14 | indent_size = 4 15 | 16 | [*.pyi] 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 3 | about: Create a report to help us improve 4 | labels: 'bug' 5 | --- 6 | 7 | # Bug report 8 | 9 | 14 | 15 | ## What's wrong 16 | 17 | 18 | 19 | ## How is that should be 20 | 21 | 22 | 23 | 32 | 33 | ## System information 34 | 35 | - `python` version: 36 | - `returns` version: 37 | - `mypy` version: 38 | 39 | - `hypothesis` version (if any): 40 | - `pytest` version (if any): 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser 2 | blank_issues_enabled: true # default 3 | contact_links: 4 | - name: >- 5 | 💬 Telegram: @drypython 6 | url: https://t.me/drypython 7 | about: Chat with dry-python devs 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # I have made things! 2 | 3 | 11 | 12 | ## Checklist 13 | 14 | 15 | 16 | - [ ] I have double checked that there are no unrelated changes in this pull request (old patches, accidental config files, etc) 17 | - [ ] I have created at least one test case for the changes I have made 18 | - [ ] I have updated the documentation for the changes I have made 19 | - [ ] I have added my changes to the `CHANGELOG.md` 20 | 21 | ## Related issues 22 | 23 | 33 | 34 | 39 | 40 | 🙏 Please, if you or your company finds `dry-python` valuable, help us sustain the project by sponsoring it transparently on https://github.com/sponsors/dry-python. As a thank you, your profile/company logo will be added to our main README which receives hundreds of unique visitors per day. 41 | -------------------------------------------------------------------------------- /.github/zizmor.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | "*": ref-pin 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | - id: check-yaml 8 | - id: check-toml 9 | - id: check-merge-conflict 10 | - id: mixed-line-ending 11 | args: [--fix=lf] 12 | - id: check-case-conflict 13 | - repo: https://github.com/python-jsonschema/check-jsonschema 14 | rev: 0.33.0 15 | hooks: 16 | - id: check-dependabot 17 | - id: check-readthedocs 18 | - id: check-github-workflows 19 | - repo: https://github.com/rhysd/actionlint 20 | rev: v1.7.7 21 | hooks: 22 | - id: actionlint 23 | - repo: https://github.com/woodruffw/zizmor-pre-commit 24 | rev: v1.8.0 25 | hooks: 26 | - id: zizmor 27 | - repo: https://github.com/shellcheck-py/shellcheck-py 28 | rev: v0.10.0.1 29 | hooks: 30 | - id: shellcheck 31 | - repo: https://github.com/tox-dev/pyproject-fmt 32 | rev: v2.6.0 33 | hooks: 34 | - id: pyproject-fmt 35 | - repo: https://github.com/astral-sh/ruff-pre-commit 36 | rev: v0.11.11 37 | hooks: 38 | - id: ruff 39 | args: ["--exit-non-zero-on-fix"] 40 | - id: ruff-format 41 | - repo: https://github.com/sphinx-contrib/sphinx-lint 42 | rev: v1.0.0 43 | hooks: 44 | - id: sphinx-lint 45 | args: [--enable=default-role] 46 | files: ^docs/ 47 | 48 | # Should be the last: 49 | - repo: meta 50 | hooks: 51 | - id: check-useless-excludes 52 | 53 | ci: 54 | autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks" 55 | autofix_prs: true 56 | autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate" 57 | autoupdate_schedule: weekly 58 | submodules: false 59 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | version: 2 3 | 4 | # Set the version of Python and other tools you might need 5 | build: 6 | os: ubuntu-lts-latest 7 | tools: {python: "3.12"} 8 | jobs: 9 | pre_create_environment: 10 | - asdf plugin add poetry 11 | - asdf install poetry latest 12 | - asdf global poetry latest 13 | - poetry config virtualenvs.create false 14 | - poetry self add poetry-plugin-export 15 | - poetry export 16 | --only main --only docs 17 | --extras check_laws --extras compatible_mypy 18 | --format=requirements.txt 19 | --output=requirements.txt 20 | 21 | python: 22 | install: 23 | - requirements: requirements.txt 24 | 25 | # Build documentation in the docs/ directory with Sphinx 26 | sphinx: 27 | configuration: docs/conf.py 28 | fail_on_warning: true 29 | 30 | formats: all 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016-2021 dry-python organization 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the 13 | distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = -W 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = returns 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/overrides.css: -------------------------------------------------------------------------------- 1 | .globaltoc > p.caption { 2 | display: block; 3 | font-size: 1.05em; 4 | font-weight: 700; 5 | text-decoration: none; 6 | margin-bottom: 1em; 7 | border: 0; 8 | } 9 | 10 | /* For some reason it did not have a scroll attached. */ 11 | 12 | .mermaid { 13 | overflow: scroll; 14 | } 15 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | returns 2 | ======= 3 | 4 | .. include:: ../README.md 5 | :parser: myst_parser.sphinx_ 6 | 7 | Contents 8 | -------- 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | pages/quickstart.rst 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | :caption: Userguide 18 | 19 | pages/container.rst 20 | pages/railway.rst 21 | pages/hkt.rst 22 | pages/interfaces.rst 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | :caption: Containers 27 | 28 | pages/maybe.rst 29 | pages/result.rst 30 | pages/io.rst 31 | pages/future.rst 32 | pages/context.rst 33 | pages/create-your-own-container.rst 34 | 35 | .. toctree:: 36 | :maxdepth: 2 37 | :caption: Composition helpers 38 | 39 | pages/pipeline.rst 40 | pages/converters.rst 41 | pages/pointfree.rst 42 | pages/methods.rst 43 | pages/do-notation.rst 44 | pages/functions.rst 45 | pages/curry.rst 46 | pages/trampolines.rst 47 | pages/types.rst 48 | 49 | .. toctree:: 50 | :maxdepth: 2 51 | :caption: Integration 52 | 53 | pages/development.rst 54 | pages/contrib/mypy_plugins.rst 55 | pages/contrib/pytest_plugins.rst 56 | pages/contrib/hypothesis_plugins.rst 57 | 58 | .. toctree:: 59 | :maxdepth: 1 60 | :caption: Changelog 61 | 62 | pages/changelog.rst 63 | 64 | 65 | Indices and tables 66 | ------------------ 67 | 68 | * :ref:`genindex` 69 | * :ref:`modindex` 70 | * :ref:`search` 71 | -------------------------------------------------------------------------------- /docs/pages/changelog.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../CHANGELOG.md 2 | :parser: myst_parser.sphinx_ 3 | -------------------------------------------------------------------------------- /docs/pages/converters.rst: -------------------------------------------------------------------------------- 1 | .. _converters: 2 | 3 | Converters 4 | ========== 5 | 6 | We have several helpers to convert containers from one type to another 7 | and back again. 8 | 9 | 10 | Maybe and Result 11 | ---------------- 12 | 13 | We have two converters to work with ``Result <-> Maybe`` transformations: 14 | 15 | .. currentmodule:: returns.converters 16 | 17 | - :func:`~.maybe_to_result` that converts ``Maybe`` to ``Result`` 18 | - :func:`~.result_to_maybe` that converts ``Result`` to ``Maybe`` 19 | 20 | That's how they work: 21 | 22 | .. code:: python 23 | 24 | >>> from returns.converters import maybe_to_result, result_to_maybe 25 | >>> from returns.maybe import Maybe, Some, Nothing 26 | >>> from returns.result import Failure, Result, Success 27 | 28 | >>> result: Result[int, Exception] = Success(1) 29 | >>> maybe: Maybe[int] = result_to_maybe(result) 30 | >>> assert maybe == Some(1) 31 | 32 | >>> new_result: Result[int, None] = maybe_to_result(maybe) 33 | >>> assert new_result == Success(1) 34 | 35 | >>> failure_with_default: Result[int, str] = maybe_to_result(Nothing, 'abc') 36 | >>> assert failure_with_default == Failure('abc') 37 | 38 | Take a note, that type changes. 39 | Also, take a note that ``Success(None)`` will be converted to ``Nothing``. 40 | 41 | 42 | flatten 43 | ------- 44 | 45 | You can also use 46 | :func:`flatten ` 47 | to merge nested containers together: 48 | 49 | .. code:: python 50 | 51 | >>> from returns.converters import flatten 52 | >>> from returns.maybe import Some 53 | >>> from returns.result import Success 54 | >>> from returns.io import IO 55 | 56 | >>> assert flatten(IO(IO(1))) == IO(1) 57 | >>> assert flatten(Some(Some(1))) == Some(1) 58 | >>> assert flatten(Success(Success(1))) == Success(1) 59 | 60 | 61 | API Reference 62 | ------------- 63 | 64 | .. automodule:: returns.converters 65 | :members: 66 | -------------------------------------------------------------------------------- /docs/pages/trampolines.rst: -------------------------------------------------------------------------------- 1 | .. _trampolines: 2 | 3 | Trampolines 4 | =========== 5 | 6 | Python does not support TCO (tail call optimization), so any recursion-based 7 | algorithms become dangerous. 8 | 9 | We cannot be sure that 10 | they won't cause ``RecursionError`` on deeply nested data. 11 | 12 | Here's why we need trampolines: they allow to replicate tail call optimization 13 | by wrapping function calls into :class:`returns.trampolines.Trampoline` objects, 14 | making recursion-based function *always* safe. 15 | 16 | Example: 17 | 18 | .. code:: python 19 | 20 | >>> from typing import Union, List 21 | >>> from returns.trampolines import Trampoline, trampoline 22 | 23 | >>> @trampoline 24 | ... def accumulate( 25 | ... numbers: List[int], 26 | ... acc: int = 0, 27 | ... ) -> Union[int, Trampoline[int]]: 28 | ... if not numbers: 29 | ... return acc 30 | ... number = number = numbers.pop() 31 | ... return Trampoline(accumulate, numbers, acc + number) 32 | 33 | >>> assert accumulate([1, 2]) == 3 34 | >>> assert accumulate([1, 2, 3]) == 6 35 | 36 | The following function is still fully type-safe: 37 | - ``Trampoline`` object uses ``ParamSpec`` to be sure that passed arguments are correct 38 | - Final return type of the function is narrowed to contain only an original type (without ``Trampoline`` implementation detail) 39 | 40 | API Reference 41 | ------------- 42 | 43 | .. automodule:: returns.trampolines 44 | :members: 45 | -------------------------------------------------------------------------------- /returns/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/__init__.py -------------------------------------------------------------------------------- /returns/_internal/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This package contains code that was "generated" via metaprogramming. 3 | 4 | This happens, because Python is not flexible enough to do most tasks 5 | common in typed functional programming. 6 | 7 | Policy: 8 | 9 | 1. We store implementations in regular ``.py`` files. 10 | 2. We store generated type annotations in ``.pyi`` files. 11 | 3. We re-export these functions into regular modules as public values. 12 | 13 | Please, do not touch this code unless you know what you are doing. 14 | """ 15 | -------------------------------------------------------------------------------- /returns/_internal/futures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/_internal/futures/__init__.py -------------------------------------------------------------------------------- /returns/_internal/futures/_reader_future_result.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from collections.abc import Awaitable, Callable 4 | from typing import TYPE_CHECKING, TypeVar 5 | 6 | from returns.primitives.hkt import Kind3, dekind 7 | from returns.result import Result, Success 8 | 9 | if TYPE_CHECKING: 10 | from returns.context import RequiresContextFutureResult 11 | 12 | _ValueType_co = TypeVar('_ValueType_co', covariant=True) 13 | _NewValueType = TypeVar('_NewValueType') 14 | _ErrorType_co = TypeVar('_ErrorType_co', covariant=True) 15 | _EnvType = TypeVar('_EnvType') 16 | 17 | 18 | async def async_bind_async( 19 | function: Callable[ 20 | [_ValueType_co], 21 | Awaitable[ 22 | Kind3[ 23 | RequiresContextFutureResult, 24 | _NewValueType, 25 | _ErrorType_co, 26 | _EnvType, 27 | ], 28 | ], 29 | ], 30 | container: RequiresContextFutureResult[ 31 | _ValueType_co, _ErrorType_co, _EnvType 32 | ], 33 | deps: _EnvType, 34 | ) -> Result[_NewValueType, _ErrorType_co]: 35 | """Async binds a coroutine with container over a value.""" 36 | inner_value = await container(deps)._inner_value # noqa: SLF001 37 | if isinstance(inner_value, Success): 38 | return await dekind( # noqa: SLF001 39 | await function(inner_value.unwrap()), 40 | )(deps)._inner_value 41 | return inner_value # type: ignore[return-value] 42 | 43 | 44 | async def async_compose_result( 45 | function: Callable[ 46 | [Result[_ValueType_co, _ErrorType_co]], 47 | Kind3[ 48 | RequiresContextFutureResult, 49 | _NewValueType, 50 | _ErrorType_co, 51 | _EnvType, 52 | ], 53 | ], 54 | container: RequiresContextFutureResult[ 55 | _ValueType_co, _ErrorType_co, _EnvType 56 | ], 57 | deps: _EnvType, 58 | ) -> Result[_NewValueType, _ErrorType_co]: 59 | """Async composes ``Result`` based function.""" 60 | new_container = dekind(function((await container(deps))._inner_value)) # noqa: SLF001 61 | return (await new_container(deps))._inner_value # noqa: SLF001 62 | -------------------------------------------------------------------------------- /returns/_internal/pipeline/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/_internal/pipeline/__init__.py -------------------------------------------------------------------------------- /returns/_internal/pipeline/flow.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | from typing import TypeVar 3 | 4 | _InstanceType = TypeVar('_InstanceType') 5 | _PipelineStepType = TypeVar('_PipelineStepType') 6 | _ReturnType = TypeVar('_ReturnType') 7 | 8 | 9 | def flow( 10 | instance: _InstanceType, 11 | *functions: _PipelineStepType, 12 | ) -> _ReturnType: # type: ignore[type-var] 13 | """ 14 | Allows to compose a value and up to multiple functions that use this value. 15 | 16 | All starts with the value itself. 17 | Each next function uses the previous result as an input parameter. 18 | 19 | We use a custom ``mypy`` plugin to make sure types are correct. 20 | Otherwise, it is currently impossible to properly type this function. 21 | 22 | Currently, ``flow`` has a hard limit of 21 steps. 23 | Because, it is not possible to type it otherwise. 24 | We need a hard limit. 25 | See: https://github.com/dry-python/returns/issues/461 26 | 27 | Here's how it should be used: 28 | 29 | .. code:: python 30 | 31 | >>> from returns.pipeline import flow 32 | 33 | >>> # => executes: str(float(int('1'))) 34 | >>> assert flow('1', int, float, str) == '1.0' 35 | 36 | This function is closely related 37 | to :func:`pipe `: 38 | 39 | .. code:: python 40 | 41 | >>> from returns.pipeline import pipe 42 | >>> assert flow('1', int, float, str) == pipe(int, float, str)('1') 43 | 44 | See also: 45 | - https://stackoverflow.com/a/41585450/4842742 46 | - https://github.com/gcanti/fp-ts/blob/master/src/pipeable.ts 47 | 48 | Requires our :ref:`mypy plugin `. 49 | """ 50 | return reduce( # type: ignore 51 | lambda composed, function: function(composed), # type: ignore 52 | functions, 53 | instance, 54 | ) 55 | -------------------------------------------------------------------------------- /returns/_internal/pipeline/pipe.py: -------------------------------------------------------------------------------- 1 | from returns._internal.pipeline.flow import flow 2 | 3 | 4 | def pipe(*functions): 5 | """ 6 | Allows to compose a value and up to 7 functions that use this value. 7 | 8 | We use a custom ``mypy`` plugin to make sure types are correct. 9 | Otherwise, it is currently impossible to properly type this function. 10 | 11 | Each next function uses the previous result as an input parameter. 12 | Here's how it should be used: 13 | 14 | .. code:: python 15 | 16 | >>> from returns.pipeline import pipe 17 | 18 | >>> # => executes: str(float(int('1'))) 19 | >>> assert pipe(int, float, str)('1') == '1.0' 20 | 21 | This function is closely related 22 | to :func:`pipe `: 23 | 24 | .. code:: python 25 | 26 | >>> from returns.pipeline import flow 27 | >>> assert pipe(int, float, str)('1') == flow('1', int, float, str) 28 | 29 | See also: 30 | - https://stackoverflow.com/a/41585450/4842742 31 | - https://github.com/gcanti/fp-ts/blob/master/src/pipeable.ts 32 | 33 | """ 34 | return lambda instance: flow(instance, *functions) 35 | -------------------------------------------------------------------------------- /returns/context/__init__.py: -------------------------------------------------------------------------------- 1 | """This module was quite a big one, so we have split it.""" 2 | 3 | from returns.context.requires_context import NoDeps as NoDeps 4 | from returns.context.requires_context import Reader as Reader 5 | from returns.context.requires_context import RequiresContext as RequiresContext 6 | from returns.context.requires_context_future_result import ( 7 | ReaderFutureResult as ReaderFutureResult, 8 | ) 9 | from returns.context.requires_context_future_result import ( 10 | ReaderFutureResultE as ReaderFutureResultE, 11 | ) 12 | from returns.context.requires_context_future_result import ( 13 | RequiresContextFutureResult as RequiresContextFutureResult, 14 | ) 15 | from returns.context.requires_context_future_result import ( 16 | RequiresContextFutureResultE as RequiresContextFutureResultE, 17 | ) 18 | from returns.context.requires_context_ioresult import ( 19 | ReaderIOResult as ReaderIOResult, 20 | ) 21 | from returns.context.requires_context_ioresult import ( 22 | ReaderIOResultE as ReaderIOResultE, 23 | ) 24 | from returns.context.requires_context_ioresult import ( 25 | RequiresContextIOResult as RequiresContextIOResult, 26 | ) 27 | from returns.context.requires_context_ioresult import ( 28 | RequiresContextIOResultE as RequiresContextIOResultE, 29 | ) 30 | from returns.context.requires_context_result import ReaderResult as ReaderResult 31 | from returns.context.requires_context_result import ( 32 | ReaderResultE as ReaderResultE, 33 | ) 34 | from returns.context.requires_context_result import ( 35 | RequiresContextResult as RequiresContextResult, 36 | ) 37 | from returns.context.requires_context_result import ( 38 | RequiresContextResultE as RequiresContextResultE, 39 | ) 40 | -------------------------------------------------------------------------------- /returns/contrib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/contrib/__init__.py -------------------------------------------------------------------------------- /returns/contrib/hypothesis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/contrib/hypothesis/__init__.py -------------------------------------------------------------------------------- /returns/contrib/hypothesis/_entrypoint.py: -------------------------------------------------------------------------------- 1 | """ 2 | Used to register all our types as hypothesis strategies. 3 | 4 | See: https://hypothesis.readthedocs.io/en/latest/strategies.html 5 | 6 | But, beware that we only register concrete types here, 7 | interfaces won't be registered! 8 | 9 | """ 10 | 11 | from __future__ import annotations 12 | 13 | from collections.abc import Callable, Sequence 14 | from typing import TYPE_CHECKING, Any, TypeVar 15 | 16 | if TYPE_CHECKING: 17 | from returns.primitives.laws import Lawful 18 | 19 | _Inst = TypeVar('_Inst', bound='Lawful') 20 | 21 | 22 | def _setup_hook() -> None: 23 | from hypothesis import strategies as st # noqa: PLC0415 24 | 25 | from returns.context import ( # noqa: PLC0415 26 | RequiresContext, 27 | RequiresContextFutureResult, 28 | RequiresContextIOResult, 29 | RequiresContextResult, 30 | ) 31 | from returns.future import Future, FutureResult # noqa: PLC0415 32 | from returns.io import IO, IOResult # noqa: PLC0415 33 | from returns.maybe import Maybe # noqa: PLC0415 34 | from returns.result import Result # noqa: PLC0415 35 | 36 | def factory( 37 | container_type: type[_Inst], 38 | ) -> Callable[[Any], st.SearchStrategy[_Inst]]: 39 | def decorator(thing: Any) -> st.SearchStrategy[_Inst]: 40 | from returns.contrib.hypothesis.containers import ( # noqa: PLC0415 41 | strategy_from_container, 42 | ) 43 | 44 | return strategy_from_container(container_type)(thing) 45 | 46 | return decorator 47 | 48 | #: Our types that we register in hypothesis 49 | #: to be working with ``st.from_type`` 50 | registered_types: Sequence[type[Lawful]] = ( 51 | Result, 52 | Maybe, 53 | IO, 54 | IOResult, 55 | Future, 56 | FutureResult, 57 | RequiresContext, 58 | RequiresContextResult, 59 | RequiresContextIOResult, 60 | RequiresContextFutureResult, 61 | ) 62 | 63 | for type_ in registered_types: 64 | st.register_type_strategy(type_, factory(type_)) 65 | -------------------------------------------------------------------------------- /returns/contrib/mypy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/contrib/mypy/__init__.py -------------------------------------------------------------------------------- /returns/contrib/mypy/_consts.py: -------------------------------------------------------------------------------- 1 | from typing import Final 2 | 3 | # Constant fullnames for typechecking 4 | # =================================== 5 | 6 | #: Used for typed ``partial`` function. 7 | TYPED_PARTIAL_FUNCTION: Final = 'returns.curry.partial' 8 | 9 | #: Used for typed ``curry`` decorator. 10 | TYPED_CURRY_FUNCTION: Final = 'returns.curry.curry' 11 | 12 | #: Used for typed ``flow`` call. 13 | TYPED_FLOW_FUNCTION: Final = 'returns._internal.pipeline.flow.flow' 14 | 15 | #: Used for typed ``pipe`` call. 16 | TYPED_PIPE_FUNCTION: Final = 'returns._internal.pipeline.pipe.pipe' 17 | TYPED_PIPE_METHOD: Final = 'returns._internal.pipeline.pipe._Pipe.__call__' 18 | 19 | #: Used for HKT emulation. 20 | TYPED_KINDN: Final = 'returns.primitives.hkt.KindN' 21 | TYPED_KINDN_ACCESS: Final = f'{TYPED_KINDN}.' 22 | TYPED_KIND_DEKIND: Final = 'returns.primitives.hkt.dekind' 23 | TYPED_KIND_KINDED_CALL: Final = 'returns.primitives.hkt.Kinded.__call__' 24 | TYPED_KIND_KINDED_GET: Final = 'returns.primitives.hkt.Kinded.__get__' 25 | 26 | #: Used for :ref:`do-notation`. 27 | DO_NOTATION_METHODS: Final = ( 28 | # Just validation: 29 | 'returns.io.IO.do', 30 | 'returns.maybe.Maybe.do', 31 | 'returns.future.Future.do', 32 | # Also infer error types: 33 | 'returns.result.Result.do', 34 | 'returns.io.IOResult.do', 35 | 'returns.future.FutureResult.do', 36 | ) 37 | -------------------------------------------------------------------------------- /returns/contrib/mypy/_features/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/contrib/mypy/_features/__init__.py -------------------------------------------------------------------------------- /returns/contrib/mypy/_features/flow.py: -------------------------------------------------------------------------------- 1 | from mypy.plugin import FunctionContext 2 | from mypy.types import Type as MypyType 3 | from mypy.types import get_proper_type 4 | 5 | from returns.contrib.mypy._typeops.inference import PipelineInference 6 | 7 | 8 | def analyze(ctx: FunctionContext) -> MypyType: 9 | """ 10 | Helps to analyze ``flow`` function calls. 11 | 12 | By default, ``mypy`` cannot infer and check this function call: 13 | 14 | .. code:: python 15 | 16 | >>> from returns.pipeline import flow 17 | >>> assert flow( 18 | ... 1, 19 | ... lambda x: x + 1, 20 | ... lambda y: y / 2, 21 | ... ) == 1.0 22 | 23 | But, this plugin can! 24 | It knows all the types for all ``lambda`` functions in the pipeline. 25 | How? 26 | 27 | 1. We use the first passed parameter as the first argument 28 | to the first passed function 29 | 2. We use parameter + function to check the call and reveal 30 | types of current pipeline step 31 | 3. We iterate through all passed function and use previous 32 | return type as a new parameter to call current function 33 | 34 | """ 35 | if not ctx.arg_types[0]: 36 | return ctx.default_return_type 37 | if not ctx.arg_types[1]: # We do require to pass `*functions` arg. 38 | ctx.api.fail('Too few arguments for "flow"', ctx.context) 39 | return ctx.default_return_type 40 | 41 | # We use custom argument type inference here, 42 | # because for some reason, `mypy` does not do it correctly. 43 | # It inferes `covariant` types incorrectly. 44 | real_arg_types = tuple( 45 | ctx.api.expr_checker.accept(arg) # type: ignore 46 | for arg in ctx.args[1] 47 | ) 48 | 49 | return PipelineInference( 50 | get_proper_type(ctx.arg_types[0][0]), 51 | ).from_callable_sequence( 52 | real_arg_types, 53 | ctx.arg_kinds[1], 54 | ctx, 55 | ) 56 | -------------------------------------------------------------------------------- /returns/contrib/mypy/_structures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/contrib/mypy/_structures/__init__.py -------------------------------------------------------------------------------- /returns/contrib/mypy/_structures/args.py: -------------------------------------------------------------------------------- 1 | from itertools import starmap 2 | from typing import NamedTuple, final 3 | 4 | from mypy.nodes import ArgKind, Context, TempNode 5 | from mypy.types import CallableType 6 | from mypy.types import Type as MypyType 7 | 8 | 9 | class _FuncArgStruct(NamedTuple): 10 | """Basic struct to represent function arguments.""" 11 | 12 | name: str | None 13 | type: MypyType # noqa: WPS125 14 | kind: ArgKind 15 | 16 | 17 | @final 18 | class FuncArg(_FuncArgStruct): 19 | """Representation of function arg with all required fields and methods.""" 20 | 21 | def expression(self, context: Context) -> TempNode: 22 | """Hack to pass unexisting `Expression` to typechecker.""" 23 | return TempNode(self.type, context=context) 24 | 25 | @classmethod 26 | def from_callable(cls, function_def: CallableType) -> list['FuncArg']: 27 | """Public constructor to create FuncArg lists from callables.""" 28 | parts = zip( 29 | function_def.arg_names, 30 | function_def.arg_types, 31 | function_def.arg_kinds, 32 | strict=False, 33 | ) 34 | return list(starmap(cls, parts)) 35 | -------------------------------------------------------------------------------- /returns/contrib/mypy/_structures/types.py: -------------------------------------------------------------------------------- 1 | from typing import TypeAlias 2 | 3 | from mypy.plugin import FunctionContext, MethodContext 4 | 5 | #: We treat them equally when working with functions or methods. 6 | CallableContext: TypeAlias = FunctionContext | MethodContext 7 | -------------------------------------------------------------------------------- /returns/contrib/mypy/_typeops/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/contrib/mypy/_typeops/__init__.py -------------------------------------------------------------------------------- /returns/contrib/mypy/_typeops/fallback.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from functools import wraps 3 | from typing import TypeVar 4 | 5 | from mypy.types import AnyType, TypeOfAny 6 | 7 | _CallableType = TypeVar('_CallableType', bound=Callable) 8 | 9 | 10 | def asserts_fallback_to_any(function: _CallableType) -> _CallableType: 11 | """ 12 | Falls back to ``Any`` when some ``assert ...`` fails in our plugin code. 13 | 14 | We often use ``assert isinstance(variable, Instance)`` 15 | as a way to ensure correctness in this plugin. 16 | But, we need a generic way to handle all 17 | possible exceptions in a single manner: 18 | just return ``Any`` and hope that someday someone reports it. 19 | 20 | """ 21 | 22 | @wraps(function) 23 | def decorator(*args, **kwargs): 24 | try: 25 | return function(*args, **kwargs) 26 | except AssertionError: 27 | # TODO: log it somehow 28 | return AnyType(TypeOfAny.implementation_artifact) 29 | 30 | return decorator # type: ignore 31 | -------------------------------------------------------------------------------- /returns/contrib/pytest/__init__.py: -------------------------------------------------------------------------------- 1 | from returns.contrib.pytest.plugin import ReturnsAsserts as ReturnsAsserts 2 | -------------------------------------------------------------------------------- /returns/interfaces/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/interfaces/__init__.py -------------------------------------------------------------------------------- /returns/interfaces/bimappable.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar 2 | 3 | from typing_extensions import Never 4 | 5 | from returns.interfaces import altable, mappable 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | 11 | 12 | class BiMappableN( 13 | mappable.MappableN[_FirstType, _SecondType, _ThirdType], 14 | altable.AltableN[_FirstType, _SecondType, _ThirdType], 15 | ): 16 | """ 17 | Allows to change both types of a container at the same time. 18 | 19 | Uses ``.map`` to change first type and ``.alt`` to change second type. 20 | 21 | See also: 22 | - https://typelevel.org/cats/typeclasses/bifunctor.html 23 | 24 | """ 25 | 26 | __slots__ = () 27 | 28 | 29 | #: Type alias for kinds with two type arguments. 30 | BiMappable2 = BiMappableN[_FirstType, _SecondType, Never] 31 | 32 | #: Type alias for kinds with three type arguments. 33 | BiMappable3 = BiMappableN[_FirstType, _SecondType, _ThirdType] 34 | -------------------------------------------------------------------------------- /returns/interfaces/bindable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from collections.abc import Callable 3 | from typing import Generic, TypeVar 4 | 5 | from typing_extensions import Never 6 | 7 | from returns.primitives.hkt import KindN 8 | 9 | _FirstType = TypeVar('_FirstType') 10 | _SecondType = TypeVar('_SecondType') 11 | _ThirdType = TypeVar('_ThirdType') 12 | _UpdatedType = TypeVar('_UpdatedType') 13 | 14 | _BindableType = TypeVar('_BindableType', bound='BindableN') 15 | 16 | 17 | class BindableN(Generic[_FirstType, _SecondType, _ThirdType]): 18 | """ 19 | Represents a "context" in which calculations can be executed. 20 | 21 | ``Bindable`` allows you to bind together 22 | a series of calculations while maintaining 23 | the context of that specific container. 24 | 25 | In contrast to :class:`returns.interfaces.lashable.LashableN`, 26 | works with the first type argument. 27 | """ 28 | 29 | __slots__ = () 30 | 31 | @abstractmethod 32 | def bind( 33 | self: _BindableType, 34 | function: Callable[ 35 | [_FirstType], 36 | KindN[_BindableType, _UpdatedType, _SecondType, _ThirdType], 37 | ], 38 | ) -> KindN[_BindableType, _UpdatedType, _SecondType, _ThirdType]: 39 | """ 40 | Applies 'function' to the result of a previous calculation. 41 | 42 | And returns a new container. 43 | """ 44 | 45 | 46 | #: Type alias for kinds with one type argument. 47 | Bindable1 = BindableN[_FirstType, Never, Never] 48 | 49 | #: Type alias for kinds with two type arguments. 50 | Bindable2 = BindableN[_FirstType, _SecondType, Never] 51 | 52 | #: Type alias for kinds with three type arguments. 53 | Bindable3 = BindableN[_FirstType, _SecondType, _ThirdType] 54 | -------------------------------------------------------------------------------- /returns/interfaces/equable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from collections.abc import Sequence 3 | from typing import ClassVar, TypeVar, final 4 | 5 | from returns.primitives.laws import ( 6 | Law, 7 | Law1, 8 | Law2, 9 | Law3, 10 | Lawful, 11 | LawSpecDef, 12 | law_definition, 13 | ) 14 | 15 | _EqualType = TypeVar('_EqualType', bound='Equable') 16 | 17 | 18 | @final 19 | class _LawSpec(LawSpecDef): 20 | """ 21 | Equality laws. 22 | 23 | Description: https://bit.ly/34D40iT 24 | """ 25 | 26 | __slots__ = () 27 | 28 | @law_definition 29 | def reflexive_law( 30 | first: _EqualType, 31 | ) -> None: 32 | """Value should be equal to itself.""" 33 | assert first.equals(first) 34 | 35 | @law_definition 36 | def symmetry_law( 37 | first: _EqualType, 38 | second: _EqualType, 39 | ) -> None: 40 | """If ``A == B`` then ``B == A``.""" 41 | assert first.equals(second) == second.equals(first) 42 | 43 | @law_definition 44 | def transitivity_law( 45 | first: _EqualType, 46 | second: _EqualType, 47 | third: _EqualType, 48 | ) -> None: 49 | """If ``A == B`` and ``B == C`` then ``A == C``.""" 50 | # We use this notation, because `first` might be equal to `third`, 51 | # but not to `second`. Example: Some(1), Some(2), Some(1) 52 | if first.equals(second) and second.equals(third): 53 | assert first.equals(third) 54 | 55 | 56 | class Equable(Lawful['Equable']): 57 | """ 58 | Interface for types that can be compared with real values. 59 | 60 | Not all types can, because some don't have the value at a time: 61 | - ``Future`` has to be awaited to get the value 62 | - ``Reader`` has to be called to get the value 63 | 64 | """ 65 | 66 | __slots__ = () 67 | 68 | _laws: ClassVar[Sequence[Law]] = ( 69 | Law1(_LawSpec.reflexive_law), 70 | Law2(_LawSpec.symmetry_law), 71 | Law3(_LawSpec.transitivity_law), 72 | ) 73 | 74 | @abstractmethod 75 | def equals(self: _EqualType, other: _EqualType) -> bool: 76 | """Type-safe equality check for values of the same type.""" 77 | -------------------------------------------------------------------------------- /returns/interfaces/lashable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from collections.abc import Callable 3 | from typing import Generic, TypeVar 4 | 5 | from typing_extensions import Never 6 | 7 | from returns.primitives.hkt import KindN 8 | 9 | _FirstType = TypeVar('_FirstType') 10 | _SecondType = TypeVar('_SecondType') 11 | _ThirdType = TypeVar('_ThirdType') 12 | _UpdatedType = TypeVar('_UpdatedType') 13 | 14 | _LashableType = TypeVar('_LashableType', bound='LashableN') 15 | 16 | 17 | class LashableN(Generic[_FirstType, _SecondType, _ThirdType]): 18 | """ 19 | Represents a "context" in which calculations can be executed. 20 | 21 | ``Rescueable`` allows you to bind together 22 | a series of calculations while maintaining 23 | the context of that specific container. 24 | 25 | In contrast to :class:`returns.interfaces.bindable.BinbdaleN`, 26 | works with the second type value. 27 | """ 28 | 29 | __slots__ = () 30 | 31 | @abstractmethod 32 | def lash( 33 | self: _LashableType, 34 | function: Callable[ 35 | [_SecondType], 36 | KindN[_LashableType, _FirstType, _UpdatedType, _ThirdType], 37 | ], 38 | ) -> KindN[_LashableType, _FirstType, _UpdatedType, _ThirdType]: 39 | """ 40 | Applies 'function' to the result of a previous calculation. 41 | 42 | And returns a new container. 43 | """ 44 | 45 | 46 | #: Type alias for kinds with two type arguments. 47 | Lashable2 = LashableN[_FirstType, _SecondType, Never] 48 | 49 | #: Type alias for kinds with three type arguments. 50 | Lashable3 = LashableN[_FirstType, _SecondType, _ThirdType] 51 | -------------------------------------------------------------------------------- /returns/interfaces/specific/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/interfaces/specific/__init__.py -------------------------------------------------------------------------------- /returns/interfaces/swappable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from collections.abc import Sequence 3 | from typing import ClassVar, TypeVar, final 4 | 5 | from typing_extensions import Never 6 | 7 | from returns.interfaces import bimappable 8 | from returns.primitives.asserts import assert_equal 9 | from returns.primitives.hkt import KindN 10 | from returns.primitives.laws import ( 11 | Law, 12 | Law1, 13 | Lawful, 14 | LawSpecDef, 15 | law_definition, 16 | ) 17 | 18 | _FirstType = TypeVar('_FirstType') 19 | _SecondType = TypeVar('_SecondType') 20 | _ThirdType = TypeVar('_ThirdType') 21 | 22 | _SwappableType = TypeVar('_SwappableType', bound='SwappableN') 23 | 24 | 25 | @final 26 | class _LawSpec(LawSpecDef): 27 | """Laws for :class:`~SwappableN` type.""" 28 | 29 | __slots__ = () 30 | 31 | @law_definition 32 | def double_swap_law( 33 | container: 'SwappableN[_FirstType, _SecondType, _ThirdType]', 34 | ) -> None: 35 | """ 36 | Swapping container twice. 37 | 38 | It ensure that we get the initial value back. 39 | In other words, swapping twice does nothing. 40 | """ 41 | assert_equal( 42 | container, 43 | container.swap().swap(), 44 | ) 45 | 46 | 47 | class SwappableN( 48 | bimappable.BiMappableN[_FirstType, _SecondType, _ThirdType], 49 | Lawful['SwappableN[_FirstType, _SecondType, _ThirdType]'], 50 | ): 51 | """Interface that allows swapping first and second type values.""" 52 | 53 | __slots__ = () 54 | 55 | _laws: ClassVar[Sequence[Law]] = (Law1(_LawSpec.double_swap_law),) 56 | 57 | @abstractmethod 58 | def swap( 59 | self: _SwappableType, 60 | ) -> KindN[_SwappableType, _SecondType, _FirstType, _ThirdType]: 61 | """Swaps first and second types in ``SwappableN``.""" 62 | 63 | 64 | #: Type alias for kinds with two type arguments. 65 | Swappable2 = SwappableN[_FirstType, _SecondType, Never] 66 | 67 | #: Type alias for kinds with three type arguments. 68 | Swappable3 = SwappableN[_FirstType, _SecondType, _ThirdType] 69 | -------------------------------------------------------------------------------- /returns/interfaces/unwrappable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from typing import Generic, TypeVar 3 | 4 | _FirstType = TypeVar('_FirstType') 5 | _SecondType = TypeVar('_SecondType') 6 | 7 | _UnwrappableType = TypeVar('_UnwrappableType', bound='Unwrappable') 8 | 9 | 10 | class Unwrappable(Generic[_FirstType, _SecondType]): 11 | """ 12 | Represents containers that can unwrap and return its wrapped value. 13 | 14 | There are no aliases or ``UnwrappableN`` for ``Unwrappable`` interface. 15 | Because it always uses two and just two types. 16 | 17 | Not all types can be ``Unwrappable`` because we do require 18 | to raise ``UnwrapFailedError`` if unwrap is not possible. 19 | """ 20 | 21 | __slots__ = () 22 | 23 | @abstractmethod 24 | def unwrap(self: _UnwrappableType) -> _FirstType: 25 | """ 26 | Custom magic method to unwrap inner value from container. 27 | 28 | Should be redefined for ones that actually have values. 29 | And for ones that raise an exception for no values. 30 | 31 | .. note:: 32 | As a part of the contract, failed ``unwrap`` calls 33 | must raise :class:`returns.primitives.exceptions.UnwrapFailedError` 34 | exception. 35 | 36 | This method is the opposite of :meth:`~Unwrapable.failure`. 37 | """ 38 | 39 | @abstractmethod 40 | def failure(self: _UnwrappableType) -> _SecondType: 41 | """ 42 | Custom magic method to unwrap inner value from the failed container. 43 | 44 | .. note:: 45 | As a part of the contract, failed ``failure`` calls 46 | must raise :class:`returns.primitives.exceptions.UnwrapFailedError` 47 | exception. 48 | 49 | This method is the opposite of :meth:`~Unwrapable.unwrap`. 50 | """ 51 | -------------------------------------------------------------------------------- /returns/methods/__init__.py: -------------------------------------------------------------------------------- 1 | from returns.methods.cond import cond as cond 2 | from returns.methods.partition import partition as partition 3 | from returns.methods.unwrap_or_failure import ( 4 | unwrap_or_failure as unwrap_or_failure, 5 | ) 6 | -------------------------------------------------------------------------------- /returns/methods/partition.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Iterable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.unwrappable import Unwrappable 5 | from returns.primitives.exceptions import UnwrapFailedError 6 | 7 | _ValueType_co = TypeVar('_ValueType_co', covariant=True) 8 | _ErrorType_co = TypeVar('_ErrorType_co', covariant=True) 9 | 10 | 11 | def partition( 12 | containers: Iterable[Unwrappable[_ValueType_co, _ErrorType_co],], 13 | ) -> tuple[list[_ValueType_co], list[_ErrorType_co]]: 14 | """ 15 | Partition a list of unwrappables into successful and failed values. 16 | 17 | Preserves order. 18 | 19 | .. code:: python 20 | 21 | >>> from returns.result import Failure, Success 22 | >>> from returns.methods import partition 23 | 24 | >>> results = [Success(1), Failure(2), Success(3), Failure(4)] 25 | >>> partition(results) 26 | ([1, 3], [2, 4]) 27 | 28 | """ 29 | successes: list[_ValueType_co] = [] 30 | failures: list[_ErrorType_co] = [] 31 | for container in containers: 32 | try: 33 | successes.append(container.unwrap()) 34 | except UnwrapFailedError: # noqa: PERF203 35 | failures.append(container.failure()) 36 | return successes, failures 37 | -------------------------------------------------------------------------------- /returns/methods/unwrap_or_failure.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar 2 | 3 | from returns.interfaces.unwrappable import Unwrappable 4 | from returns.pipeline import is_successful 5 | 6 | _FirstType = TypeVar('_FirstType') 7 | _SecondType = TypeVar('_SecondType') 8 | 9 | 10 | def unwrap_or_failure( 11 | container: Unwrappable[_FirstType, _SecondType], 12 | ) -> _FirstType | _SecondType: 13 | """ 14 | Unwraps either successful or failed value. 15 | 16 | .. code:: python 17 | 18 | >>> from returns.io import IO, IOSuccess, IOFailure 19 | >>> from returns.methods import unwrap_or_failure 20 | 21 | >>> assert unwrap_or_failure(IOSuccess(1)) == IO(1) 22 | >>> assert unwrap_or_failure(IOFailure('a')) == IO('a') 23 | 24 | """ 25 | if is_successful(container): 26 | return container.unwrap() 27 | return container.failure() 28 | -------------------------------------------------------------------------------- /returns/pipeline.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from returns._internal.pipeline.flow import flow as flow 4 | from returns._internal.pipeline.managed import managed as managed 5 | from returns._internal.pipeline.pipe import pipe as pipe 6 | from returns.interfaces.unwrappable import Unwrappable 7 | from returns.primitives.exceptions import UnwrapFailedError 8 | 9 | 10 | # TODO: add overloads for specific types, so it can narrow them with `TypeIs` 11 | def is_successful(container: Unwrappable[Any, Any]) -> bool: 12 | """ 13 | Determines if a container was successful or not. 14 | 15 | .. code:: python 16 | 17 | >>> from returns.maybe import Some, Nothing 18 | >>> from returns.result import Failure, Success 19 | >>> from returns.io import IOSuccess, IOFailure 20 | 21 | >>> assert is_successful(Some(1)) 22 | >>> assert not is_successful(Nothing) 23 | 24 | >>> assert is_successful(Success(1)) 25 | >>> assert not is_successful(Failure(1)) 26 | 27 | >>> assert is_successful(IOSuccess(1)) 28 | >>> assert not is_successful(IOFailure(1)) 29 | 30 | This function can work with containers 31 | that are instance of :class:`returns.interfaces.unwrappable.Unwrappable`. 32 | 33 | """ 34 | try: 35 | container.unwrap() 36 | except UnwrapFailedError: 37 | return False 38 | return True 39 | -------------------------------------------------------------------------------- /returns/pointfree/alt.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.altable import AltableN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _AltableKind = TypeVar('_AltableKind', bound=AltableN) 13 | 14 | 15 | def alt( 16 | function: Callable[[_SecondType], _UpdatedType], 17 | ) -> Kinded[ 18 | Callable[ 19 | [KindN[_AltableKind, _FirstType, _SecondType, _ThirdType]], 20 | KindN[_AltableKind, _FirstType, _UpdatedType, _ThirdType], 21 | ] 22 | ]: 23 | """ 24 | Lifts function to be wrapped in a container for better composition. 25 | 26 | In other words, it modifies the function's 27 | signature from: 28 | ``a -> b`` 29 | to: 30 | ``Container[a] -> Container[b]`` 31 | 32 | This is how it should be used: 33 | 34 | .. code:: python 35 | 36 | >>> from returns.io import IOFailure, IOSuccess 37 | >>> from returns.pointfree import alt 38 | 39 | >>> def example(argument: int) -> float: 40 | ... return argument / 2 41 | 42 | >>> assert alt(example)(IOSuccess(1)) == IOSuccess(1) 43 | >>> assert alt(example)(IOFailure(4)) == IOFailure(2.0) 44 | 45 | Note, that this function works for all containers with ``.alt`` method. 46 | See :class:`returns.primitives.interfaces.altable.AltableN` for more info. 47 | 48 | """ 49 | 50 | @kinded 51 | def factory( 52 | container: KindN[_AltableKind, _FirstType, _SecondType, _ThirdType], 53 | ) -> KindN[_AltableKind, _FirstType, _UpdatedType, _ThirdType]: 54 | return container.alt(function) 55 | 56 | return factory 57 | -------------------------------------------------------------------------------- /returns/pointfree/apply.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.applicative import ApplicativeN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _ApplicativeKind = TypeVar('_ApplicativeKind', bound=ApplicativeN) 13 | 14 | 15 | def apply( 16 | container: KindN[ 17 | _ApplicativeKind, 18 | Callable[[_FirstType], _UpdatedType], 19 | _SecondType, 20 | _ThirdType, 21 | ], 22 | ) -> Kinded[ 23 | Callable[ 24 | [KindN[_ApplicativeKind, _FirstType, _SecondType, _ThirdType]], 25 | KindN[_ApplicativeKind, _UpdatedType, _SecondType, _ThirdType], 26 | ] 27 | ]: 28 | """ 29 | Turns container containing a function into a callable. 30 | 31 | In other words, it modifies the function 32 | signature from: 33 | ``Container[a -> b]`` 34 | to: 35 | ``Container[a] -> Container[b]`` 36 | 37 | This is how it should be used: 38 | 39 | .. code:: python 40 | 41 | >>> from returns.pointfree import apply 42 | >>> from returns.maybe import Some, Nothing 43 | 44 | >>> def example(argument: int) -> int: 45 | ... return argument + 1 46 | 47 | >>> assert apply(Some(example))(Some(1)) == Some(2) 48 | >>> assert apply(Some(example))(Nothing) == Nothing 49 | >>> assert apply(Nothing)(Some(1)) == Nothing 50 | >>> assert apply(Nothing)(Nothing) == Nothing 51 | 52 | Note, that this function works for all containers with ``.apply`` method. 53 | See :class:`returns.interfaces.applicative.ApplicativeN` for more info. 54 | 55 | """ 56 | 57 | @kinded 58 | def factory( 59 | other: KindN[_ApplicativeKind, _FirstType, _SecondType, _ThirdType], 60 | ) -> KindN[_ApplicativeKind, _UpdatedType, _SecondType, _ThirdType]: 61 | return other.apply(container) 62 | 63 | return factory 64 | -------------------------------------------------------------------------------- /returns/pointfree/bimap.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.bimappable import BiMappableN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | 11 | _UpdatedType1 = TypeVar('_UpdatedType1') 12 | _UpdatedType2 = TypeVar('_UpdatedType2') 13 | 14 | _BiMappableKind = TypeVar('_BiMappableKind', bound=BiMappableN) 15 | 16 | 17 | def bimap( 18 | on_first: Callable[[_FirstType], _UpdatedType1], 19 | on_second: Callable[[_SecondType], _UpdatedType2], 20 | ) -> Kinded[ 21 | Callable[ 22 | [KindN[_BiMappableKind, _FirstType, _SecondType, _ThirdType]], 23 | KindN[_BiMappableKind, _UpdatedType1, _UpdatedType2, _ThirdType], 24 | ] 25 | ]: 26 | """ 27 | Maps container on both: first and second arguments. 28 | 29 | Can be used to synchronize state on both success and failure. 30 | 31 | This is how it should be used: 32 | 33 | .. code:: python 34 | 35 | >>> from returns.io import IOSuccess, IOFailure 36 | >>> from returns.pointfree import bimap 37 | 38 | >>> def first(argument: int) -> float: 39 | ... return argument / 2 40 | 41 | >>> def second(argument: str) -> bool: 42 | ... return bool(argument) 43 | 44 | >>> assert bimap(first, second)(IOSuccess(1)) == IOSuccess(0.5) 45 | >>> assert bimap(first, second)(IOFailure('')) == IOFailure(False) 46 | 47 | Note, that this function works 48 | for all containers with ``.map`` and ``.alt`` methods. 49 | See :class:`returns.primitives.interfaces.bimappable.BiMappableN` 50 | for more info. 51 | 52 | """ 53 | 54 | @kinded 55 | def factory( 56 | container: KindN[_BiMappableKind, _FirstType, _SecondType, _ThirdType], 57 | ) -> KindN[_BiMappableKind, _UpdatedType1, _UpdatedType2, _ThirdType]: 58 | return container.map(on_first).alt(on_second) 59 | 60 | return factory 61 | -------------------------------------------------------------------------------- /returns/pointfree/bind.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.bindable import BindableN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _BindableKind = TypeVar('_BindableKind', bound=BindableN) 13 | 14 | 15 | def bind( 16 | function: Callable[ 17 | [_FirstType], 18 | KindN[_BindableKind, _UpdatedType, _SecondType, _ThirdType], 19 | ], 20 | ) -> Kinded[ 21 | Callable[ 22 | [KindN[_BindableKind, _FirstType, _SecondType, _ThirdType]], 23 | KindN[_BindableKind, _UpdatedType, _SecondType, _ThirdType], 24 | ] 25 | ]: 26 | """ 27 | Turns function's input parameter from a regular value to a container. 28 | 29 | In other words, it modifies the function 30 | signature from: 31 | ``a -> Container[b]`` 32 | to: 33 | ``Container[a] -> Container[b]`` 34 | 35 | Similar to :func:`returns.pointfree.lash`, 36 | but works for successful containers. 37 | This is how it should be used: 38 | 39 | .. code:: python 40 | 41 | >>> from returns.pointfree import bind 42 | >>> from returns.maybe import Maybe, Some, Nothing 43 | 44 | >>> def example(argument: int) -> Maybe[int]: 45 | ... return Some(argument + 1) 46 | 47 | >>> assert bind(example)(Some(1)) == Some(2) 48 | >>> assert bind(example)(Nothing) == Nothing 49 | 50 | Note, that this function works for all containers with ``.bind`` method. 51 | See :class:`returns.primitives.interfaces.bindable.BindableN` for more info. 52 | 53 | """ 54 | 55 | @kinded 56 | def factory( 57 | container: KindN[_BindableKind, _FirstType, _SecondType, _ThirdType], 58 | ) -> KindN[_BindableKind, _UpdatedType, _SecondType, _ThirdType]: 59 | return container.bind(function) 60 | 61 | return factory 62 | -------------------------------------------------------------------------------- /returns/pointfree/bind_async.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Awaitable, Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.specific.future import FutureLikeN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _FutureKind = TypeVar('_FutureKind', bound=FutureLikeN) 13 | 14 | 15 | def bind_async( 16 | function: Callable[ 17 | [_FirstType], 18 | Awaitable[KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType]], 19 | ], 20 | ) -> Kinded[ 21 | Callable[ 22 | [KindN[_FutureKind, _FirstType, _SecondType, _ThirdType]], 23 | KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType], 24 | ] 25 | ]: 26 | """ 27 | Compose a container and ``async`` function returning a container. 28 | 29 | In other words, it modifies the function's 30 | signature from: 31 | ``a -> Awaitable[Container[b]]`` 32 | to: 33 | ``Container[a] -> Container[b]`` 34 | 35 | This is how it should be used: 36 | 37 | .. code:: python 38 | 39 | >>> import anyio 40 | >>> from returns.future import Future 41 | >>> from returns.io import IO 42 | >>> from returns.pointfree import bind_async 43 | 44 | >>> async def coroutine(x: int) -> Future[str]: 45 | ... return Future.from_value(str(x + 1)) 46 | 47 | >>> bound = bind_async(coroutine)(Future.from_value(1)) 48 | >>> assert anyio.run(bound.awaitable) == IO('2') 49 | 50 | Note, that this function works 51 | for all containers with ``.bind_async`` method. 52 | See :class:`returns.primitives.interfaces.specific.future.FutureLikeN` 53 | for more info. 54 | 55 | """ 56 | 57 | @kinded 58 | def factory( 59 | container: KindN[_FutureKind, _FirstType, _SecondType, _ThirdType], 60 | ) -> KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType]: 61 | return container.bind_async(function) 62 | 63 | return factory 64 | -------------------------------------------------------------------------------- /returns/pointfree/bind_async_future.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Awaitable, Callable 2 | from typing import TypeVar 3 | 4 | from returns.future import Future 5 | from returns.interfaces.specific.future import FutureLikeN 6 | from returns.primitives.hkt import Kinded, KindN, kinded 7 | 8 | _FirstType = TypeVar('_FirstType') 9 | _SecondType = TypeVar('_SecondType') 10 | _ThirdType = TypeVar('_ThirdType') 11 | _UpdatedType = TypeVar('_UpdatedType') 12 | 13 | _FutureKind = TypeVar('_FutureKind', bound=FutureLikeN) 14 | 15 | 16 | def bind_async_future( 17 | function: Callable[ 18 | [_FirstType], 19 | Awaitable[Future[_UpdatedType]], 20 | ], 21 | ) -> Kinded[ 22 | Callable[ 23 | [KindN[_FutureKind, _FirstType, _SecondType, _ThirdType]], 24 | KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType], 25 | ] 26 | ]: 27 | """ 28 | Compose a container and async function returning ``Future``. 29 | 30 | In other words, it modifies the function 31 | signature from: 32 | ``a -> Awaitable[Future[b]]`` 33 | to: 34 | ``Container[a] -> Container[b]`` 35 | 36 | This is how it should be used: 37 | 38 | .. code:: python 39 | 40 | >>> import anyio 41 | >>> from returns.pointfree import bind_async_future 42 | >>> from returns.future import Future 43 | >>> from returns.io import IO 44 | 45 | >>> async def example(argument: int) -> Future[int]: 46 | ... return Future.from_value(argument + 1) 47 | 48 | >>> assert anyio.run( 49 | ... bind_async_future(example)(Future.from_value(1)).awaitable, 50 | ... ) == IO(2) 51 | 52 | Note, that this function works 53 | for all containers with ``.bind_async_future`` method. 54 | See :class:`returns.primitives.interfaces.specific.future.FutureLikeN` 55 | for more info. 56 | 57 | """ 58 | 59 | @kinded 60 | def factory( 61 | container: KindN[_FutureKind, _FirstType, _SecondType, _ThirdType], 62 | ) -> KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType]: 63 | return container.bind_async_future(function) 64 | 65 | return factory 66 | -------------------------------------------------------------------------------- /returns/pointfree/bind_awaitable.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Awaitable, Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.specific.future import FutureLikeN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _FutureKind = TypeVar('_FutureKind', bound=FutureLikeN) 13 | 14 | 15 | def bind_awaitable( 16 | function: Callable[[_FirstType], Awaitable[_UpdatedType]], 17 | ) -> Kinded[ 18 | Callable[ 19 | [KindN[_FutureKind, _FirstType, _SecondType, _ThirdType]], 20 | KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType], 21 | ] 22 | ]: 23 | """ 24 | Composes a container a regular ``async`` function. 25 | 26 | This function should return plain, non-container value. 27 | 28 | In other words, it modifies the function's 29 | signature from: 30 | ``a -> Awaitable[b]`` 31 | to: 32 | ``Container[a] -> Container[b]`` 33 | 34 | This is how it should be used: 35 | 36 | .. code:: python 37 | 38 | >>> import anyio 39 | >>> from returns.future import Future 40 | >>> from returns.io import IO 41 | >>> from returns.pointfree import bind_awaitable 42 | 43 | >>> async def coroutine(x: int) -> int: 44 | ... return x + 1 45 | 46 | >>> assert anyio.run( 47 | ... bind_awaitable(coroutine)(Future.from_value(1)).awaitable, 48 | ... ) == IO(2) 49 | 50 | Note, that this function works 51 | for all containers with ``.bind_awaitable`` method. 52 | See :class:`returns.primitives.interfaces.specific.future.FutureLikeN` 53 | for more info. 54 | 55 | """ 56 | 57 | @kinded 58 | def factory( 59 | container: KindN[_FutureKind, _FirstType, _SecondType, _ThirdType], 60 | ) -> KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType]: 61 | return container.bind_awaitable(function) 62 | 63 | return factory 64 | -------------------------------------------------------------------------------- /returns/pointfree/bind_future.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.future import Future 5 | from returns.interfaces.specific.future import FutureLikeN 6 | from returns.primitives.hkt import Kinded, KindN, kinded 7 | 8 | _FirstType = TypeVar('_FirstType') 9 | _SecondType = TypeVar('_SecondType') 10 | _ThirdType = TypeVar('_ThirdType') 11 | _UpdatedType = TypeVar('_UpdatedType') 12 | 13 | _FutureKind = TypeVar('_FutureKind', bound=FutureLikeN) 14 | 15 | 16 | def bind_future( 17 | function: Callable[[_FirstType], Future[_UpdatedType]], 18 | ) -> Kinded[ 19 | Callable[ 20 | [KindN[_FutureKind, _FirstType, _SecondType, _ThirdType]], 21 | KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType], 22 | ] 23 | ]: 24 | """ 25 | Compose a container and sync function returning ``Future``. 26 | 27 | In other words, it modifies the function 28 | signature from: 29 | ``a -> Future[b]`` 30 | to: 31 | ``Container[a] -> Container[b]`` 32 | 33 | Similar to :func:`returns.pointfree.lash`, 34 | but works for successful containers. 35 | This is how it should be used: 36 | 37 | .. code:: python 38 | 39 | >>> import anyio 40 | >>> from returns.pointfree import bind_future 41 | >>> from returns.future import Future 42 | >>> from returns.io import IO 43 | 44 | >>> def example(argument: int) -> Future[int]: 45 | ... return Future.from_value(argument + 1) 46 | 47 | >>> assert anyio.run( 48 | ... bind_future(example)(Future.from_value(1)).awaitable, 49 | ... ) == IO(2) 50 | 51 | Note, that this function works 52 | for all containers with ``.bind_future`` method. 53 | See :class:`returns.primitives.interfaces.specific.future.FutureLikeN` 54 | for more info. 55 | 56 | """ 57 | 58 | @kinded 59 | def factory( 60 | container: KindN[_FutureKind, _FirstType, _SecondType, _ThirdType], 61 | ) -> KindN[_FutureKind, _UpdatedType, _SecondType, _ThirdType]: 62 | return container.bind_future(function) 63 | 64 | return factory 65 | -------------------------------------------------------------------------------- /returns/pointfree/bind_io.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from collections.abc import Callable 4 | from typing import TYPE_CHECKING, TypeVar 5 | 6 | from returns.interfaces.specific.io import IOLikeN 7 | from returns.primitives.hkt import Kinded, KindN, kinded 8 | 9 | if TYPE_CHECKING: 10 | from returns.io import IO # noqa: WPS433 11 | 12 | _FirstType_contra = TypeVar('_FirstType_contra', contravariant=True) 13 | _SecondType = TypeVar('_SecondType') 14 | _ThirdType_contra = TypeVar('_ThirdType_contra', contravariant=True) 15 | _UpdatedType_co = TypeVar('_UpdatedType_co', covariant=True) 16 | 17 | _IOLikeKind = TypeVar('_IOLikeKind', bound=IOLikeN) 18 | 19 | 20 | def bind_io( 21 | function: Callable[[_FirstType_contra], IO[_UpdatedType_co]], 22 | ) -> Kinded[ 23 | Callable[ 24 | [KindN[_IOLikeKind, _FirstType_contra, _SecondType, _ThirdType_contra]], 25 | KindN[_IOLikeKind, _UpdatedType_co, _SecondType, _ThirdType_contra], 26 | ] 27 | ]: 28 | """ 29 | Composes successful container with a function that returns a container. 30 | 31 | In other words, it modifies the function's 32 | signature from: 33 | ``a -> IO[b]`` 34 | to: 35 | ``Container[a, c] -> Container[b, c]`` 36 | 37 | .. code:: python 38 | 39 | >>> from returns.io import IOSuccess, IOFailure 40 | >>> from returns.io import IO 41 | >>> from returns.pointfree import bind_io 42 | 43 | >>> def returns_io(arg: int) -> IO[int]: 44 | ... return IO(arg + 1) 45 | 46 | >>> bound = bind_io(returns_io) 47 | >>> assert bound(IO(1)) == IO(2) 48 | >>> assert bound(IOSuccess(1)) == IOSuccess(2) 49 | >>> assert bound(IOFailure(1)) == IOFailure(1) 50 | 51 | """ 52 | 53 | @kinded 54 | def factory( 55 | container: KindN[ 56 | _IOLikeKind, _FirstType_contra, _SecondType, _ThirdType_contra 57 | ], 58 | ) -> KindN[_IOLikeKind, _UpdatedType_co, _SecondType, _ThirdType_contra]: 59 | return container.bind_io(function) 60 | 61 | return factory 62 | -------------------------------------------------------------------------------- /returns/pointfree/bind_ioresult.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from collections.abc import Callable 4 | from typing import TYPE_CHECKING, TypeVar 5 | 6 | from returns.interfaces.specific.ioresult import IOResultLikeN 7 | from returns.primitives.hkt import Kinded, KindN, kinded 8 | 9 | if TYPE_CHECKING: 10 | from returns.io import IOResult # noqa: WPS433 11 | 12 | _FirstType = TypeVar('_FirstType') 13 | _SecondType = TypeVar('_SecondType') 14 | _ThirdType = TypeVar('_ThirdType') 15 | _UpdatedType = TypeVar('_UpdatedType') 16 | 17 | _IOResultLikeKind = TypeVar('_IOResultLikeKind', bound=IOResultLikeN) 18 | 19 | 20 | def bind_ioresult( 21 | function: Callable[[_FirstType], IOResult[_UpdatedType, _SecondType]], 22 | ) -> Kinded[ 23 | Callable[ 24 | [KindN[_IOResultLikeKind, _FirstType, _SecondType, _ThirdType]], 25 | KindN[_IOResultLikeKind, _UpdatedType, _SecondType, _ThirdType], 26 | ] 27 | ]: 28 | """ 29 | Composes successful container with a function that returns a container. 30 | 31 | In other words, it modifies the function's 32 | signature from: 33 | ``a -> IOResult[b, c]`` 34 | to: 35 | ``Container[a, c] -> Container[b, c]`` 36 | 37 | .. code:: python 38 | 39 | >>> from returns.io import IOResult, IOSuccess 40 | >>> from returns.context import RequiresContextIOResult 41 | >>> from returns.pointfree import bind_ioresult 42 | 43 | >>> def returns_ioresult(arg: int) -> IOResult[int, str]: 44 | ... return IOSuccess(arg + 1) 45 | 46 | >>> bound = bind_ioresult(returns_ioresult) 47 | >>> assert bound(IOSuccess(1)) == IOSuccess(2) 48 | >>> assert bound( 49 | ... RequiresContextIOResult.from_value(1), 50 | ... )(...) == IOSuccess(2) 51 | 52 | """ 53 | 54 | @kinded 55 | def factory( 56 | container: KindN[ 57 | _IOResultLikeKind, 58 | _FirstType, 59 | _SecondType, 60 | _ThirdType, 61 | ], 62 | ) -> KindN[_IOResultLikeKind, _UpdatedType, _SecondType, _ThirdType]: 63 | return container.bind_ioresult(function) 64 | 65 | return factory 66 | -------------------------------------------------------------------------------- /returns/pointfree/bind_optional.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.specific.maybe import MaybeLikeN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _MaybeLikeKind = TypeVar('_MaybeLikeKind', bound=MaybeLikeN) 13 | 14 | 15 | def bind_optional( 16 | function: Callable[[_FirstType], _UpdatedType | None], 17 | ) -> Kinded[ 18 | Callable[ 19 | [KindN[_MaybeLikeKind, _FirstType, _SecondType, _ThirdType]], 20 | KindN[_MaybeLikeKind, _UpdatedType, _SecondType, _ThirdType], 21 | ] 22 | ]: 23 | """ 24 | Binds a function returning optional value over a container. 25 | 26 | In other words, it modifies the function's 27 | signature from: 28 | ``a -> Optional[b]`` 29 | to: 30 | ``Container[a] -> Container[b]`` 31 | 32 | .. code:: python 33 | 34 | >>> from typing import Optional 35 | >>> from returns.pointfree import bind_optional 36 | >>> from returns.maybe import Some, Nothing 37 | 38 | >>> def example(argument: int) -> Optional[int]: 39 | ... return argument + 1 if argument > 0 else None 40 | 41 | >>> assert bind_optional(example)(Some(1)) == Some(2) 42 | >>> assert bind_optional(example)(Some(0)) == Nothing 43 | >>> assert bind_optional(example)(Nothing) == Nothing 44 | 45 | Note, that this function works 46 | for all containers with ``.bind_optional`` method. 47 | See :class:`returns.primitives.interfaces.specific.maybe._MaybeLikeKind` 48 | for more info. 49 | 50 | """ 51 | 52 | @kinded 53 | def factory( 54 | container: KindN[_MaybeLikeKind, _FirstType, _SecondType, _ThirdType], 55 | ) -> KindN[_MaybeLikeKind, _UpdatedType, _SecondType, _ThirdType]: 56 | return container.bind_optional(function) 57 | 58 | return factory 59 | -------------------------------------------------------------------------------- /returns/pointfree/bind_result.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from collections.abc import Callable 4 | from typing import TYPE_CHECKING, TypeVar 5 | 6 | from returns.interfaces.specific.result import ResultLikeN 7 | from returns.primitives.hkt import Kinded, KindN, kinded 8 | 9 | if TYPE_CHECKING: 10 | from returns.result import Result # noqa: WPS433 11 | 12 | _FirstType = TypeVar('_FirstType') 13 | _SecondType = TypeVar('_SecondType') 14 | _ThirdType = TypeVar('_ThirdType') 15 | _UpdatedType = TypeVar('_UpdatedType') 16 | 17 | _ResultLikeKind = TypeVar('_ResultLikeKind', bound=ResultLikeN) 18 | 19 | 20 | def bind_result( 21 | function: Callable[[_FirstType], Result[_UpdatedType, _SecondType]], 22 | ) -> Kinded[ 23 | Callable[ 24 | [KindN[_ResultLikeKind, _FirstType, _SecondType, _ThirdType]], 25 | KindN[_ResultLikeKind, _UpdatedType, _SecondType, _ThirdType], 26 | ] 27 | ]: 28 | """ 29 | Composes successful container with a function that returns a container. 30 | 31 | In other words, it modifies the function's 32 | signature from: 33 | ``a -> Result[b, c]`` 34 | to: 35 | ``Container[a, c] -> Container[b, c]`` 36 | 37 | .. code:: python 38 | 39 | >>> from returns.io import IOSuccess 40 | >>> from returns.context import RequiresContextResult 41 | >>> from returns.result import Result, Success 42 | >>> from returns.pointfree import bind_result 43 | 44 | >>> def returns_result(arg: int) -> Result[int, str]: 45 | ... return Success(arg + 1) 46 | 47 | >>> bound = bind_result(returns_result) 48 | >>> assert bound(IOSuccess(1)) == IOSuccess(2) 49 | >>> assert bound(RequiresContextResult.from_value(1))(...) == Success(2) 50 | 51 | """ 52 | 53 | @kinded 54 | def factory( 55 | container: KindN[_ResultLikeKind, _FirstType, _SecondType, _ThirdType], 56 | ) -> KindN[_ResultLikeKind, _UpdatedType, _SecondType, _ThirdType]: 57 | return container.bind_result(function) 58 | 59 | return factory 60 | -------------------------------------------------------------------------------- /returns/pointfree/compose_result.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.specific.ioresult import IOResultLikeN 5 | from returns.primitives.hkt import Kind3, Kinded, kinded 6 | from returns.result import Result 7 | 8 | _FirstType = TypeVar('_FirstType') 9 | _NewFirstType = TypeVar('_NewFirstType') 10 | _SecondType = TypeVar('_SecondType') 11 | _ThirdType = TypeVar('_ThirdType') 12 | 13 | _IOResultLikeKind = TypeVar('_IOResultLikeKind', bound=IOResultLikeN) 14 | 15 | 16 | def compose_result( 17 | function: Callable[ 18 | [Result[_FirstType, _SecondType]], 19 | Kind3[_IOResultLikeKind, _NewFirstType, _SecondType, _ThirdType], 20 | ], 21 | ) -> Kinded[ 22 | Callable[ 23 | [Kind3[_IOResultLikeKind, _FirstType, _SecondType, _ThirdType]], 24 | Kind3[_IOResultLikeKind, _NewFirstType, _SecondType, _ThirdType], 25 | ] 26 | ]: 27 | """ 28 | Composes inner ``Result`` with ``IOResultLike`` returning function. 29 | 30 | Can be useful when you need an access to both states of the result. 31 | 32 | .. code:: python 33 | 34 | >>> from returns.io import IOResult, IOSuccess, IOFailure 35 | >>> from returns.pointfree import compose_result 36 | >>> from returns.result import Result 37 | 38 | >>> def modify_string(container: Result[str, str]) -> IOResult[str, str]: 39 | ... return IOResult.from_result( 40 | ... container.map(str.upper).alt(str.lower), 41 | ... ) 42 | 43 | >>> assert compose_result(modify_string)( 44 | ... IOSuccess('success') 45 | ... ) == IOSuccess('SUCCESS') 46 | >>> assert compose_result(modify_string)( 47 | ... IOFailure('FAILURE') 48 | ... ) == IOFailure('failure') 49 | 50 | """ 51 | 52 | @kinded 53 | def factory( 54 | container: Kind3[ 55 | _IOResultLikeKind, 56 | _FirstType, 57 | _SecondType, 58 | _ThirdType, 59 | ], 60 | ) -> Kind3[_IOResultLikeKind, _NewFirstType, _SecondType, _ThirdType]: 61 | return container.compose_result(function) 62 | 63 | return factory 64 | -------------------------------------------------------------------------------- /returns/pointfree/lash.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.lashable import LashableN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _LashableKind = TypeVar('_LashableKind', bound=LashableN) 13 | 14 | 15 | def lash( 16 | function: Callable[ 17 | [_SecondType], 18 | KindN[_LashableKind, _FirstType, _UpdatedType, _ThirdType], 19 | ], 20 | ) -> Kinded[ 21 | Callable[ 22 | [KindN[_LashableKind, _FirstType, _SecondType, _ThirdType]], 23 | KindN[_LashableKind, _FirstType, _UpdatedType, _ThirdType], 24 | ] 25 | ]: 26 | """ 27 | Turns function's input parameter from a regular value to a container. 28 | 29 | In other words, it modifies the function 30 | signature from: 31 | ``a -> Container[b]`` 32 | to: 33 | ``Container[a] -> Container[b]`` 34 | 35 | Similar to :func:`returns.pointfree.bind`, but works for failed containers. 36 | 37 | This is how it should be used: 38 | 39 | .. code:: python 40 | 41 | >>> from returns.pointfree import lash 42 | >>> from returns.result import Success, Failure, Result 43 | 44 | >>> def example(argument: int) -> Result[str, int]: 45 | ... return Success(argument + 1) 46 | 47 | >>> assert lash(example)(Success('a')) == Success('a') 48 | >>> assert lash(example)(Failure(1)) == Success(2) 49 | 50 | Note, that this function works for all containers with ``.lash`` method. 51 | See :class:`returns.interfaces.lashable.Lashable` for more info. 52 | 53 | """ 54 | 55 | @kinded 56 | def factory( 57 | container: KindN[_LashableKind, _FirstType, _SecondType, _ThirdType], 58 | ) -> KindN[_LashableKind, _FirstType, _UpdatedType, _ThirdType]: 59 | return container.lash(function) 60 | 61 | return factory 62 | -------------------------------------------------------------------------------- /returns/pointfree/map.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.interfaces.mappable import MappableN 5 | from returns.primitives.hkt import Kinded, KindN, kinded 6 | 7 | _FirstType = TypeVar('_FirstType') 8 | _SecondType = TypeVar('_SecondType') 9 | _ThirdType = TypeVar('_ThirdType') 10 | _UpdatedType = TypeVar('_UpdatedType') 11 | 12 | _MappableKind = TypeVar('_MappableKind', bound=MappableN) 13 | 14 | 15 | def map_( 16 | function: Callable[[_FirstType], _UpdatedType], 17 | ) -> Kinded[ 18 | Callable[ 19 | [KindN[_MappableKind, _FirstType, _SecondType, _ThirdType]], 20 | KindN[_MappableKind, _UpdatedType, _SecondType, _ThirdType], 21 | ] 22 | ]: 23 | """ 24 | Lifts function to be wrapped in a container for better composition. 25 | 26 | In other words, it modifies the function's 27 | signature from: 28 | ``a -> b`` 29 | to: ``Container[a] -> Container[b]`` 30 | 31 | This is how it should be used: 32 | 33 | .. code:: python 34 | 35 | >>> from returns.io import IO 36 | >>> from returns.pointfree import map_ 37 | 38 | >>> def example(argument: int) -> float: 39 | ... return argument / 2 40 | 41 | >>> assert map_(example)(IO(1)) == IO(0.5) 42 | 43 | Note, that this function works for all containers with ``.map`` method. 44 | See :class:`returns.primitives.interfaces.mappable.MappableN` for more info. 45 | 46 | See also: 47 | - https://wiki.haskell.org/Lifting 48 | 49 | """ 50 | 51 | @kinded 52 | def factory( 53 | container: KindN[_MappableKind, _FirstType, _SecondType, _ThirdType], 54 | ) -> KindN[_MappableKind, _UpdatedType, _SecondType, _ThirdType]: 55 | return container.map(function) 56 | 57 | return factory 58 | -------------------------------------------------------------------------------- /returns/primitives/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/primitives/__init__.py -------------------------------------------------------------------------------- /returns/primitives/asserts.py: -------------------------------------------------------------------------------- 1 | def assert_equal( 2 | first, 3 | second, 4 | *, 5 | deps=None, 6 | backend: str = 'asyncio', 7 | ) -> None: 8 | """ 9 | Custom ``assert`` function to compare two any containers. 10 | 11 | The important note here is that 12 | this ``assert`` should probably used in tests. 13 | Not real application code. 14 | 15 | It will call all ``Reader`` based containers and ``await`` 16 | all ``Future`` based ones. 17 | 18 | It also works recursively. 19 | For example, ``ReaderFutureResult`` will be called and then awaited. 20 | 21 | You can specify different dependencies to call your containers. 22 | And different backends to ``await`` then using ``anyio``. 23 | 24 | By the way, ``anyio`` should be installed separately. 25 | """ 26 | assert _convert( 27 | first, 28 | deps=deps, 29 | backend=backend, 30 | ) == _convert( 31 | second, 32 | deps=deps, 33 | backend=backend, 34 | ), f'{first} == {second}' 35 | 36 | 37 | def _convert(container, *, deps, backend: str): 38 | from returns.interfaces.specific import future, reader # noqa: PLC0415 39 | 40 | if isinstance(container, future.AwaitableFutureN): 41 | import anyio # noqa: PLC0415 42 | 43 | return _convert( 44 | anyio.run(container.awaitable, backend=backend), 45 | deps=deps, 46 | backend=backend, 47 | ) 48 | if isinstance(container, reader.Contextable): 49 | return _convert( 50 | container(deps), 51 | deps=deps, 52 | backend=backend, 53 | ) 54 | return container 55 | -------------------------------------------------------------------------------- /returns/primitives/exceptions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from returns.interfaces.unwrappable import Unwrappable # noqa: WPS433 7 | 8 | 9 | class UnwrapFailedError(Exception): 10 | """Raised when a container can not be unwrapped into a meaningful value.""" 11 | 12 | __slots__ = ('halted_container',) 13 | 14 | def __init__(self, container: Unwrappable) -> None: 15 | """ 16 | Saves halted container in the inner state. 17 | 18 | So, this container can later be unpacked from this exception 19 | and used as a regular value. 20 | """ 21 | super().__init__() 22 | self.halted_container = container 23 | 24 | def __reduce__(self): # noqa: WPS603 25 | """Custom reduce method for pickle protocol. 26 | 27 | This helps properly reconstruct the exception during unpickling. 28 | """ 29 | return ( 30 | self.__class__, # callable 31 | (self.halted_container,), # args to callable 32 | ) 33 | 34 | 35 | class ImmutableStateError(AttributeError): 36 | """ 37 | Raised when a container is forced to be mutated. 38 | 39 | It is a sublclass of ``AttributeError`` for two reasons: 40 | 41 | 1. It seems kinda reasonable to expect ``AttributeError`` 42 | on attribute modification 43 | 2. It is used inside ``typing.py`` this way, 44 | we do have several typing features that requires that behaviour 45 | 46 | See: https://github.com/dry-python/returns/issues/394 47 | """ 48 | -------------------------------------------------------------------------------- /returns/primitives/types.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from typing_extensions import Never, Self 4 | 5 | from returns.primitives.exceptions import ImmutableStateError 6 | 7 | 8 | class Immutable: 9 | """ 10 | Helper type for objects that should be immutable. 11 | 12 | When applied, each instance becomes immutable. 13 | Nothing can be added or deleted from it. 14 | 15 | .. code:: pycon 16 | :force: 17 | 18 | >>> from returns.primitives.types import Immutable 19 | >>> class MyModel(Immutable): 20 | ... ... 21 | 22 | >>> model = MyModel() 23 | >>> model.prop = 1 24 | Traceback (most recent call last): 25 | ... 26 | returns.primitives.exceptions.ImmutableStateError 27 | 28 | See :class:`returns.primitives.container.BaseContainer` for examples. 29 | 30 | """ 31 | 32 | __slots__ = () 33 | 34 | def __copy__(self) -> Self: 35 | """Returns itself.""" 36 | return self 37 | 38 | def __deepcopy__(self, memo: dict[Any, Any]) -> Self: 39 | """Returns itself.""" 40 | return self 41 | 42 | def __setattr__(self, attr_name: str, attr_value: Any) -> Never: 43 | """Makes inner state of the containers immutable for modification.""" 44 | raise ImmutableStateError 45 | 46 | def __delattr__(self, attr_name: str) -> Never: # noqa: WPS603 47 | """Makes inner state of the containers immutable for deletion.""" 48 | raise ImmutableStateError 49 | -------------------------------------------------------------------------------- /returns/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/returns/py.typed -------------------------------------------------------------------------------- /returns/unsafe.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar 2 | 3 | from returns.io import IO 4 | 5 | _ValueType = TypeVar('_ValueType') 6 | 7 | 8 | def unsafe_perform_io(wrapped_in_io: IO[_ValueType]) -> _ValueType: 9 | """ 10 | Compatibility utility and escape mechanism from ``IO`` world. 11 | 12 | Just unwraps the internal value 13 | from :class:`returns.io.IO` container. 14 | Should be used with caution! 15 | Since it might be overused by lazy and ignorant developers. 16 | 17 | It is recommended to have only one place (module / file) 18 | in your program where you allow unsafe operations. 19 | 20 | We recommend to use ``import-linter`` to enforce this rule. 21 | 22 | .. code:: python 23 | 24 | >>> from returns.io import IO 25 | >>> assert unsafe_perform_io(IO(1)) == 1 26 | 27 | See also: 28 | - https://github.com/seddonym/import-linter 29 | 30 | """ 31 | return wrapped_in_io._inner_value # noqa: SLF001 32 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context/test_context.py: -------------------------------------------------------------------------------- 1 | from copy import copy, deepcopy 2 | 3 | import pytest 4 | 5 | from returns.context import RequiresContext 6 | from returns.primitives.exceptions import ImmutableStateError 7 | 8 | 9 | def test_requires_context_immutable() -> None: 10 | """Ensures that Context is immutable.""" 11 | with pytest.raises(ImmutableStateError): 12 | RequiresContext.from_value(1).abc = 1 13 | 14 | 15 | def test_requires_context_immutable_copy() -> None: 16 | """Ensures that Context returns it self when passed to copy function.""" 17 | context = RequiresContext.from_value(1) 18 | assert context is copy(context) 19 | 20 | 21 | def test_requires_context_immutable_deepcopy() -> None: 22 | """Ensures that Context returns it self when passed to deepcopy function.""" 23 | context = RequiresContext.from_value(1) 24 | assert context is deepcopy(context) 25 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context/test_context_equality.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | 3 | from returns.context import RequiresContext 4 | 5 | 6 | def _same_function(some_arg: int) -> Callable[[float], float]: 7 | return lambda other: other / some_arg 8 | 9 | 10 | def test_equality() -> None: 11 | """Ensures that containers can be compared.""" 12 | assert RequiresContext(_same_function) == RequiresContext(_same_function) 13 | 14 | 15 | def test_nonequality() -> None: 16 | """Ensures that containers can be compared.""" 17 | assert RequiresContext(_same_function) != RequiresContext(str) 18 | assert RequiresContext.from_value(1) != RequiresContext.from_value(1) 19 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context/test_context_utils.py: -------------------------------------------------------------------------------- 1 | from returns.context import RequiresContext 2 | 3 | 4 | def test_context_ask(): 5 | """Ensures that ``ask`` method works correctly.""" 6 | assert RequiresContext[str, int].ask()(1) == 1 7 | assert RequiresContext[int, str].ask()('a') == 'a' 8 | 9 | 10 | def test_requires_context_from_value(): 11 | """Ensures that ``from_value`` method works correctly.""" 12 | assert RequiresContext.from_value(1)(RequiresContext.no_args) == 1 13 | assert RequiresContext.from_value(2)(1) == 2 14 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context_ioresult/test_context_ioresult.py: -------------------------------------------------------------------------------- 1 | from copy import copy, deepcopy 2 | 3 | import pytest 4 | 5 | from returns.context import RequiresContextIOResult 6 | from returns.primitives.exceptions import ImmutableStateError 7 | 8 | 9 | def test_requires_context_result_immutable(): 10 | """Ensures that container is immutable.""" 11 | with pytest.raises(ImmutableStateError): 12 | RequiresContextIOResult.from_value(1).abc = 1 13 | 14 | 15 | def test_requires_context_result_immutable_copy(): 16 | """Ensures that helper returns it self when passed to copy function.""" 17 | context_ioresult = RequiresContextIOResult.from_value(1) 18 | assert context_ioresult is copy(context_ioresult) 19 | 20 | 21 | def test_requires_context_result_immutable_deepcopy(): # noqa: WPS118 22 | """Ensures that helper returns it self when passed to deepcopy function.""" 23 | requires_context = RequiresContextIOResult.from_value(1) 24 | assert requires_context is deepcopy(requires_context) 25 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context_ioresult/test_requires_context_ioresult.py: -------------------------------------------------------------------------------- 1 | from returns.context import RequiresContextIOResultE 2 | from returns.io import IOSuccess 3 | 4 | 5 | def test_regression394(): 6 | """ 7 | It used to raise ``ImmutableStateError`` for type aliases. 8 | 9 | Here we use the minimal reproduction sample. 10 | 11 | .. code:: python 12 | 13 | Traceback (most recent call last): 14 | File "ex.py", line 18, in 15 | get_ip_addr("https://google.com") 16 | File "ex.py", line 13, in get_ip_addr 17 | return RequiresContextIOResultE(lambda _: IOSuccess(1)) 18 | File "../3.7.7/lib/python3.7/typing.py", line 677, in __call__ 19 | result.__orig_class__ = self 20 | File "../returns/returns/primitives/types.py", line 42, in __setattr__ 21 | raise ImmutableStateError() 22 | returns.primitives.exceptions.ImmutableStateError 23 | 24 | See: https://github.com/dry-python/returns/issues/394 25 | 26 | """ 27 | RequiresContextIOResultE(lambda _: IOSuccess(1)) 28 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context_ioresult/test_requires_context_ioresult_cast.py: -------------------------------------------------------------------------------- 1 | from returns.context import ( 2 | ReaderIOResult, 3 | ReaderIOResultE, 4 | RequiresContextIOResult, 5 | RequiresContextIOResultE, 6 | ) 7 | 8 | 9 | def _function(arg: int) -> RequiresContextIOResultE[float, int]: 10 | if arg == 0: 11 | return RequiresContextIOResult.from_failure( 12 | ZeroDivisionError('Divided by 0'), 13 | ) 14 | return RequiresContextIOResult.from_value(10 / arg) 15 | 16 | 17 | def test_requires_context_ioresulte(): 18 | """Ensures that RequiresContextIOResultE correctly typecast.""" 19 | container: RequiresContextIOResult[float, Exception, int] = _function(1) 20 | assert container(0) == RequiresContextIOResult.from_value(10.0)(0) 21 | 22 | 23 | def test_requires_context_io_aliases(): 24 | """Ensures that ReaderIOResult correctly typecast.""" 25 | container: ReaderIOResultE[float, int] = _function(1) 26 | container2: ReaderIOResult[float, Exception, int] = _function(1) 27 | container3: ReaderIOResultE[float, int] = ReaderIOResultE.from_value( 28 | 10.0, 29 | ) 30 | container4: ReaderIOResultE[float, int] = ReaderIOResult.from_value(10.0) 31 | 32 | assert container(0) == container2(0) == container3(0) == container4(0) 33 | assert container(0) == RequiresContextIOResult.from_value(10.0)(0) 34 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context_result/test_context_result.py: -------------------------------------------------------------------------------- 1 | from copy import copy, deepcopy 2 | 3 | import pytest 4 | 5 | from returns.context import RequiresContextResult 6 | from returns.primitives.exceptions import ImmutableStateError 7 | 8 | 9 | def test_immutable_copy(): 10 | """Ensures that helper returns it self when passed to copy function.""" 11 | context_result = RequiresContextResult.from_value(1) 12 | assert context_result is copy(context_result) 13 | 14 | 15 | def test_immutable_deepcopy(): 16 | """Ensures that helper returns it self when passed to deepcopy function.""" 17 | context_result = RequiresContextResult.from_value(1) 18 | assert context_result is deepcopy(context_result) 19 | 20 | 21 | def test_requires_context_result_immutable(): 22 | """Ensures that container is immutable.""" 23 | with pytest.raises(ImmutableStateError): 24 | RequiresContextResult.from_value(1).abc = 1 25 | -------------------------------------------------------------------------------- /tests/test_context/test_requires_context_result/test_requires_context_result_cast.py: -------------------------------------------------------------------------------- 1 | from returns.context import ( 2 | ReaderResult, 3 | ReaderResultE, 4 | RequiresContextResult, 5 | RequiresContextResultE, 6 | ) 7 | 8 | 9 | def _function(arg: int) -> RequiresContextResultE[float, int]: 10 | if arg == 0: 11 | return RequiresContextResult.from_failure( 12 | ZeroDivisionError('Divided by 0'), 13 | ) 14 | return RequiresContextResult.from_value(10 / arg) 15 | 16 | 17 | def test_requires_context_resulte(): 18 | """Ensures that RequiresContextResultE correctly typecast.""" 19 | container: RequiresContextResult[float, Exception, int] = _function(1) 20 | assert container(0) == RequiresContextResult.from_value(10.0)(0) 21 | 22 | 23 | def test_requires_context_aliases(): 24 | """Ensures that ReaderResult correctly typecast.""" 25 | container: ReaderResultE[float, int] = _function(1) 26 | container2: ReaderResult[float, Exception, int] = _function(1) 27 | container3: ReaderResultE[float, int] = ReaderResultE.from_value( 28 | 10.0, 29 | ) 30 | container4: ReaderResultE[float, int] = ReaderResult.from_value(10.0) 31 | 32 | assert container(0) == container2(0) == container3(0) == container4(0) 33 | assert container(0) == RequiresContextResult.from_value(10.0)(0) 34 | -------------------------------------------------------------------------------- /tests/test_contrib/test_hypothesis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dry-python/returns/2eea4580c95aabd6ba2a0e869cb9860d203f6b2b/tests/test_contrib/test_hypothesis/__init__.py -------------------------------------------------------------------------------- /tests/test_contrib/test_hypothesis/test_laws/test_custom_type_applicative.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.contrib.hypothesis.laws import check_all_laws 5 | from returns.interfaces import applicative 6 | from returns.primitives.container import BaseContainer 7 | from returns.primitives.hkt import Kind1, SupportsKind1 8 | 9 | _ValueType = TypeVar('_ValueType') 10 | _NewValueType = TypeVar('_NewValueType') 11 | 12 | 13 | class _Wrapper( 14 | BaseContainer, 15 | SupportsKind1['_Wrapper', _ValueType], 16 | applicative.Applicative1[_ValueType], 17 | ): 18 | _inner_value: _ValueType 19 | 20 | def __init__(self, inner_value: _ValueType) -> None: 21 | super().__init__(inner_value) 22 | 23 | def map( 24 | self, 25 | function: Callable[[_ValueType], _NewValueType], 26 | ) -> '_Wrapper[_NewValueType]': 27 | return _Wrapper(function(self._inner_value)) 28 | 29 | def apply( 30 | self, 31 | container: Kind1['_Wrapper', Callable[[_ValueType], _NewValueType]], 32 | ) -> '_Wrapper[_NewValueType]': 33 | function = container._inner_value # noqa: SLF001 34 | return _Wrapper(function(self._inner_value)) 35 | 36 | @classmethod 37 | def from_value( 38 | cls, 39 | inner_value: _NewValueType, 40 | ) -> '_Wrapper[_NewValueType]': 41 | return _Wrapper(inner_value) 42 | 43 | 44 | check_all_laws(_Wrapper) 45 | -------------------------------------------------------------------------------- /tests/test_contrib/test_hypothesis/test_laws/test_custom_type_with_init.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | from returns.contrib.hypothesis.laws import check_all_laws 5 | from returns.interfaces import equable, mappable 6 | from returns.primitives.container import BaseContainer, container_equality 7 | from returns.primitives.hkt import SupportsKind1 8 | 9 | _ValueType = TypeVar('_ValueType') 10 | _NewValueType = TypeVar('_NewValueType') 11 | 12 | 13 | class _Wrapper( 14 | BaseContainer, 15 | SupportsKind1['_Wrapper', _ValueType], 16 | mappable.Mappable1[_ValueType], 17 | equable.Equable, 18 | ): 19 | _inner_value: _ValueType 20 | 21 | def __init__(self, inner_value: _ValueType) -> None: 22 | super().__init__(inner_value) 23 | 24 | equals = container_equality 25 | 26 | def map( 27 | self, 28 | function: Callable[[_ValueType], _NewValueType], 29 | ) -> '_Wrapper[_NewValueType]': 30 | return _Wrapper(function(self._inner_value)) 31 | 32 | 33 | check_all_laws(_Wrapper, use_init=True) 34 | -------------------------------------------------------------------------------- /tests/test_contrib/test_hypothesis/test_laws/test_unsatisfiable_type.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | import pytest 5 | from hypothesis.errors import ResolutionFailed 6 | 7 | from returns.contrib.hypothesis.laws import check_all_laws 8 | from returns.interfaces import mappable 9 | from returns.primitives.container import BaseContainer 10 | from returns.primitives.hkt import SupportsKind1 11 | 12 | pytestmark = pytest.mark.xfail(raises=ResolutionFailed) 13 | 14 | _ValueType = TypeVar('_ValueType') 15 | _NewValueType = TypeVar('_NewValueType') 16 | 17 | 18 | class _WithInitNoFlag( 19 | BaseContainer, 20 | SupportsKind1['_WithInitNoFlag', _ValueType], 21 | mappable.Mappable1[_ValueType], 22 | ): 23 | """Does not have any ways to be constructed.""" 24 | 25 | def map( 26 | self, 27 | function: Callable[[_ValueType], _NewValueType], 28 | ) -> '_WithInitNoFlag[_NewValueType]': 29 | """We need `map` to have `laws`, should not be called.""" 30 | raise NotImplementedError 31 | 32 | 33 | check_all_laws(_WithInitNoFlag) 34 | -------------------------------------------------------------------------------- /tests/test_contrib/test_hypothesis/test_laws/test_user_specified_strategy.py: -------------------------------------------------------------------------------- 1 | from hypothesis import strategies as st 2 | from test_hypothesis.test_laws import test_custom_type_applicative 3 | 4 | from returns.contrib.hypothesis.laws import check_all_laws 5 | 6 | container_type = test_custom_type_applicative._Wrapper # noqa: SLF001 7 | 8 | check_all_laws( 9 | container_type, 10 | container_strategy=st.builds(container_type, st.integers()), 11 | ) 12 | -------------------------------------------------------------------------------- /tests/test_contrib/test_hypothesis/test_laws/test_wrong_custom_type_with_init.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | from typing import TypeVar 3 | 4 | import pytest 5 | 6 | from returns.contrib.hypothesis.laws import check_all_laws 7 | from returns.interfaces import mappable 8 | from returns.primitives.container import BaseContainer 9 | from returns.primitives.hkt import SupportsKind1 10 | 11 | pytestmark = pytest.mark.xfail(raises=AssertionError) 12 | 13 | _ValueType = TypeVar('_ValueType') 14 | _NewValueType = TypeVar('_NewValueType') 15 | 16 | 17 | class _Wrapper( 18 | BaseContainer, 19 | SupportsKind1['_Wrapper', _ValueType], 20 | mappable.Mappable1[_ValueType], 21 | ): 22 | _inner_value: _ValueType 23 | 24 | def __init__(self, inner_value: _ValueType) -> None: 25 | super().__init__(inner_value) 26 | 27 | def map( 28 | self, 29 | function: Callable[[_ValueType], _NewValueType], 30 | ) -> '_Wrapper[_NewValueType]': 31 | return _Wrapper( 32 | f'wrong-{function(self._inner_value)}', # type: ignore 33 | ) 34 | 35 | 36 | check_all_laws(_Wrapper, use_init=True) 37 | -------------------------------------------------------------------------------- /tests/test_contrib/test_hypothesis/test_type_resolver.py: -------------------------------------------------------------------------------- 1 | from typing import Generic, TypeVar 2 | 3 | from hypothesis import strategies as st 4 | 5 | from returns.contrib.hypothesis.type_resolver import ( 6 | look_up_strategy, 7 | strategies_for_types, 8 | ) 9 | 10 | _ValueType = TypeVar('_ValueType') 11 | 12 | 13 | class _Wrapper1(Generic[_ValueType]): 14 | _inner_value: _ValueType 15 | 16 | 17 | class _Wrapper2(Generic[_ValueType]): 18 | _inner_value: _ValueType 19 | 20 | 21 | def test_types_without_strategies() -> None: # noqa: WPS210 22 | """Check that it temporarily resolves a type that has no strategy.""" 23 | strategy_before1 = look_up_strategy(_Wrapper1) 24 | strategy_before2 = look_up_strategy(_Wrapper2) 25 | 26 | with strategies_for_types({ 27 | _Wrapper1: st.builds(_Wrapper1, st.integers()), 28 | _Wrapper2: st.builds(_Wrapper2, st.text()), 29 | }): 30 | strategy_inside1 = look_up_strategy(_Wrapper1) 31 | strategy_inside2 = look_up_strategy(_Wrapper2) 32 | 33 | strategy_after1 = look_up_strategy(_Wrapper1) 34 | strategy_after2 = look_up_strategy(_Wrapper2) 35 | 36 | assert strategy_before1 is None 37 | assert strategy_before2 is None 38 | assert str(strategy_inside1) == 'builds(_Wrapper1, integers())' 39 | assert str(strategy_inside2) == 'builds(_Wrapper2, text())' 40 | assert strategy_after1 is None 41 | assert strategy_after2 is None 42 | 43 | 44 | def test_type_with_strategy() -> None: 45 | """Check that it restores the original strategy.""" 46 | with strategies_for_types({_Wrapper1: st.builds(_Wrapper1, st.integers())}): 47 | strategy_before = look_up_strategy(_Wrapper1) 48 | 49 | with strategies_for_types({_Wrapper1: st.builds(_Wrapper1, st.text())}): 50 | strategy_inside = look_up_strategy(_Wrapper1) 51 | 52 | strategy_after = look_up_strategy(_Wrapper1) 53 | 54 | assert str(strategy_before) == 'builds(_Wrapper1, integers())' 55 | assert str(strategy_inside) == 'builds(_Wrapper1, text())' 56 | assert str(strategy_after) == 'builds(_Wrapper1, integers())' 57 | -------------------------------------------------------------------------------- /tests/test_examples/test_future/test_future_result.py: -------------------------------------------------------------------------------- 1 | import asyncio # we use `asyncio` only as an example, you can use any io lib 2 | from collections.abc import Sequence 3 | from typing import Final, cast 4 | 5 | import httpx # you would need to `pip install httpx` 6 | from typing_extensions import TypedDict 7 | 8 | from returns.future import FutureResult, future_safe 9 | from returns.io import IOResultE 10 | from returns.iterables import Fold 11 | 12 | _URL: Final = 'https://jsonplaceholder.typicode.com/posts/{0}' 13 | 14 | 15 | class _Post(TypedDict): 16 | id: int 17 | user_id: int 18 | title: str 19 | body: str 20 | 21 | 22 | @future_safe 23 | async def _fetch_post(post_id: int) -> _Post: 24 | # Ideally, we can use `ReaderFutureResult` to provide `client` from deps. 25 | async with httpx.AsyncClient(timeout=5) as client: 26 | response = await client.get(_URL.format(post_id)) 27 | response.raise_for_status() 28 | return cast(_Post, response.json()) # or validate the response 29 | 30 | 31 | def _show_titles( 32 | number_of_posts: int, 33 | ) -> Sequence[FutureResult[str, Exception]]: 34 | def factory(post: _Post) -> str: # noqa: FURB118 35 | return post['title'] 36 | 37 | return [ 38 | # Notice how easily we compose async and sync functions: 39 | _fetch_post(post_id).map(factory) 40 | # TODO: try `for post_id in (2, 1, 0):` to see how async errors work 41 | for post_id in range(1, number_of_posts + 1) 42 | ] 43 | 44 | 45 | async def main() -> IOResultE[Sequence[str]]: 46 | """ 47 | Main entrypoint for the async world. 48 | 49 | Let's fetch 3 titles of posts asynchronously. 50 | We use `gather` to run requests in "parallel". 51 | """ 52 | futures: Sequence[IOResultE[str]] = await asyncio.gather(*_show_titles(3)) 53 | return Fold.collect(futures, IOResultE.from_value(())) 54 | 55 | 56 | if __name__ == '__main__': 57 | print(asyncio.run(main())) # noqa: WPS421 58 | # > 63 | -------------------------------------------------------------------------------- /tests/test_examples/test_io/test_ioresult_container/test_ioresult_pattern_matching.py: -------------------------------------------------------------------------------- 1 | from returns.io import IOFailure, IOResult, IOSuccess 2 | from returns.result import Success 3 | 4 | container: IOResult[int, str] = IOSuccess(42) 5 | match container: 6 | # Matches if the result stored inside `IOSuccess` is `42` 7 | # We need to use `Success` until the custom matching protocol 8 | # is released. For more information, please visit: 9 | # https://www.python.org/dev/peps/pep-0622/#custom-matching-protocol 10 | case IOSuccess(Success(42)): 11 | print('Result is "42"') 12 | 13 | # Matches any `IOSuccess` instance 14 | # and binds its value to the `value` variable 15 | case IOSuccess(value): 16 | print(f'Result is "{value}"') 17 | 18 | # Matches any `IOFailure` instance 19 | case IOFailure(_): 20 | print('A failure was occurred') 21 | -------------------------------------------------------------------------------- /tests/test_examples/test_maybe/test_maybe_pattern_matching.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Final 3 | 4 | from returns.maybe import Maybe, Nothing, Some 5 | 6 | 7 | @dataclass 8 | class _Book: 9 | book_id: int 10 | name: str 11 | 12 | 13 | _BOOK_LIST: Final = ( 14 | _Book(book_id=1, name='Category Theory for Programmers'), 15 | _Book(book_id=2, name='Fluent Python'), 16 | _Book(book_id=3, name='Learn You Some Erlang for Great Good'), 17 | _Book(book_id=4, name='Learn You a Haskell for Great Good'), 18 | ) 19 | 20 | 21 | def _find_book(book_id: int) -> Maybe[_Book]: 22 | for book in _BOOK_LIST: 23 | if book.book_id == book_id: 24 | return Some(book) 25 | return Nothing 26 | 27 | 28 | if __name__ == '__main__': 29 | desired_book = _find_book(2) 30 | match desired_book: 31 | # Matches any `Some` instance that contains a book named `Fluent Python` 32 | case Some(_Book(name='Fluent Python')): 33 | print('"Fluent Python" was found') 34 | 35 | # Matches any `Some` instance and binds its value to the `book` variable 36 | case Some(book): 37 | print(f'Book found: {book.name}') 38 | 39 | # Matches `Nothing` instance 40 | case Maybe.empty: 41 | print('Not found the desired book!') 42 | -------------------------------------------------------------------------------- /tests/test_examples/test_result/test_result_pattern_matching.py: -------------------------------------------------------------------------------- 1 | from returns.result import Failure, Success, safe 2 | 3 | 4 | @safe 5 | def div(first_number: int, second_number: int) -> int: # noqa: FURB118 6 | return first_number // second_number 7 | 8 | 9 | match div(1, 0): 10 | # Matches if the result stored inside `Success` is `10` 11 | case Success(10): 12 | print('Result is "10"') 13 | 14 | # Matches any `Success` instance and binds its value to the `value` variable 15 | case Success(value): 16 | print(f'Result is "{value}"') 17 | 18 | # Matches if the result stored inside `Failure` is `ZeroDivisionError` 19 | case Failure(ZeroDivisionError()): 20 | print('"ZeroDivisionError" was raised') 21 | 22 | # Matches any `Failure` instance 23 | case Failure(_): 24 | print('The division was a failure') 25 | -------------------------------------------------------------------------------- /tests/test_functions/test_compose.py: -------------------------------------------------------------------------------- 1 | from returns.functions import compose 2 | 3 | 4 | def _first(argument: int) -> str: 5 | return str(argument) 6 | 7 | 8 | def _second(argument: str) -> bool: 9 | return bool(argument) 10 | 11 | 12 | def test_function_composition(): 13 | """Ensures that functions can be composed and return type is correct.""" 14 | second_after_first = compose(_first, _second) 15 | 16 | assert second_after_first(1) is True 17 | assert second_after_first(0) is True 18 | -------------------------------------------------------------------------------- /tests/test_functions/test_raise_exception.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.functions import raise_exception 4 | from returns.result import Failure, Success 5 | 6 | 7 | class _CustomError(Exception): 8 | """Just for the test.""" 9 | 10 | 11 | @pytest.mark.parametrize( 12 | 'exception_type', 13 | [ 14 | TypeError, 15 | ValueError, 16 | _CustomError, 17 | ], 18 | ) 19 | def test_raise_regular_exception(exception_type: type[Exception]): 20 | """Ensures that regular exception can be thrown.""" 21 | with pytest.raises(exception_type): 22 | raise_exception(exception_type()) 23 | 24 | 25 | def test_failure_can_be_alted(): 26 | """Ensures that exceptions can work with Failures.""" 27 | failure = Failure(ValueError('Message')) 28 | with pytest.raises(ValueError, match='Message'): 29 | failure.alt(raise_exception) 30 | 31 | 32 | def test_success_is_not_touched(): 33 | """Ensures that exceptions can work with Success.""" 34 | assert Success(1).alt(raise_exception) == Success(1) 35 | -------------------------------------------------------------------------------- /tests/test_future/test_future_container/test_asyncize_decorator.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.future import asyncify 4 | 5 | 6 | @asyncify 7 | def _function(arg: int) -> float: 8 | return arg / 2 9 | 10 | 11 | @pytest.mark.anyio 12 | async def test_asyncify_decorator(): 13 | """Ensure that function marked with ``@asyncify`` is awaitable.""" 14 | coro = _function(2) 15 | 16 | assert await coro == 1 17 | -------------------------------------------------------------------------------- /tests/test_future/test_future_container/test_future_decorator.py: -------------------------------------------------------------------------------- 1 | import anyio 2 | import pytest 3 | 4 | from returns.future import Future, future 5 | from returns.io import IO 6 | 7 | 8 | @future 9 | async def _coro(arg: int) -> float: 10 | assert isinstance(arg, int) 11 | await anyio.sleep(0) 12 | return arg / 2 13 | 14 | 15 | @pytest.mark.anyio 16 | async def test_safe_decorator(): 17 | """Ensure that coroutine marked with ``@future`` returns ``Future``.""" 18 | future_instance = _coro(1) 19 | 20 | assert isinstance(future_instance, Future) 21 | assert await future_instance == IO(0.5) 22 | -------------------------------------------------------------------------------- /tests/test_future/test_future_container/test_future_equality.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.future import Future 4 | 5 | 6 | def test_nonequality(): 7 | """Ensures that containers can be compared.""" 8 | assert Future.from_value(1) != Future.from_value(1) 9 | assert hash(Future.from_value(1)) 10 | 11 | 12 | @pytest.mark.anyio 13 | async def test_equality(): 14 | """Ensures that containers are not compared to regular values.""" 15 | assert await Future.from_value(2) == await Future.from_value(2) 16 | -------------------------------------------------------------------------------- /tests/test_future/test_future_container/test_future_units.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Awaitable 2 | from typing import Any 3 | 4 | import pytest 5 | 6 | from returns.future import Future, FutureResult 7 | from returns.io import IO 8 | 9 | 10 | @pytest.mark.anyio 11 | async def test_inner_value(subtests): 12 | """Ensure that coroutine correct value is preserved for all units.""" 13 | containers: list[Awaitable[Any]] = [ 14 | # We have to define these values inside the test, because 15 | # otherwise `anyio` will `await` reused coroutines. 16 | # And they have to be fresh. That's why we use subtests for it. 17 | Future.from_value(1), 18 | Future.from_io(IO(1)), 19 | Future.from_future_result(FutureResult.from_value(1)), 20 | Future.from_future_result(FutureResult.from_failure(1)), 21 | ] 22 | for container in containers: 23 | with subtests.test(container=container): 24 | assert isinstance(await container, IO) 25 | -------------------------------------------------------------------------------- /tests/test_future/test_future_result/test_future_result_decorator.py: -------------------------------------------------------------------------------- 1 | import anyio 2 | import pytest 3 | 4 | from returns.future import FutureResult, future_safe 5 | from returns.io import IOFailure, IOSuccess 6 | 7 | 8 | @future_safe 9 | async def _coro(arg: int) -> float: 10 | assert isinstance(arg, int) 11 | await anyio.sleep(0) 12 | return 1 / arg 13 | 14 | 15 | @future_safe(exceptions=(ZeroDivisionError,)) 16 | async def _coro_two(arg: int) -> float: 17 | assert isinstance(arg, int) 18 | await anyio.sleep(0) 19 | return 1 / arg 20 | 21 | 22 | @future_safe((ZeroDivisionError,)) 23 | async def _coro_three(arg: int | str) -> float: 24 | assert isinstance(arg, int) 25 | await anyio.sleep(0) 26 | return 1 / arg 27 | 28 | 29 | @pytest.mark.anyio 30 | async def test_future_safe_decorator(): 31 | """Ensure that coroutine marked with ``@future_safe``.""" 32 | future_instance = _coro(2) 33 | 34 | assert isinstance(future_instance, FutureResult) 35 | assert await future_instance == IOSuccess(0.5) 36 | 37 | 38 | @pytest.mark.anyio 39 | async def test_future_safe_decorator_failure(): 40 | """Ensure that coroutine marked with ``@future_safe``.""" 41 | future_instance = _coro(0) 42 | 43 | assert isinstance(future_instance, FutureResult) 44 | assert isinstance(await future_instance, IOFailure) 45 | 46 | 47 | @pytest.mark.anyio 48 | async def test_future_safe_decorator_w_expected_error(subtests): 49 | """Ensure that coroutine marked with ``@future_safe``.""" 50 | expected = '>' 51 | 52 | for future_instance in (_coro_two(0), _coro_three(0)): 53 | with subtests.test(future_instance=future_instance): 54 | assert isinstance(future_instance, FutureResult) 55 | inner_result = await future_instance 56 | assert str(inner_result) == expected 57 | 58 | 59 | @pytest.mark.anyio 60 | @pytest.mark.xfail(raises=AssertionError) 61 | async def test_future_safe_decorator_w_unexpected_error(): 62 | """Ensure that coroutine marked with ``@future_safe``.""" 63 | await _coro_three('0') 64 | -------------------------------------------------------------------------------- /tests/test_future/test_future_result/test_future_result_equality.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.future import FutureResult 4 | 5 | 6 | def test_nonequality(): 7 | """Ensures that containers can be compared.""" 8 | assert FutureResult.from_value(1) != FutureResult.from_value(1) 9 | assert hash(FutureResult.from_value(1)) 10 | 11 | 12 | @pytest.mark.anyio 13 | async def test_equality(): 14 | """Ensures that containers are not compared to regular values.""" 15 | assert await FutureResult.from_value( 16 | 2, 17 | ) == await FutureResult.from_value(2) 18 | -------------------------------------------------------------------------------- /tests/test_future/test_future_result/test_future_result_units.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.future import Future, FutureResult 4 | from returns.io import IO, IOFailure, IOSuccess 5 | from returns.result import Failure, Success 6 | 7 | 8 | @pytest.mark.anyio 9 | async def test_inner_value(subtests): 10 | """Ensure that coroutine correct value is preserved for all units.""" 11 | containers = [ 12 | # We have to define these values inside the test, because 13 | # otherwise `anyio` will `await` reused coroutines. 14 | # And they have to be fresh. That's why we use subtests for it. 15 | FutureResult.from_value(1), 16 | FutureResult.from_failure(1), 17 | FutureResult.from_io(IO(1)), 18 | FutureResult.from_failed_io(IO(1)), 19 | FutureResult.from_ioresult(IOSuccess(1)), 20 | FutureResult.from_ioresult(IOFailure(1)), 21 | FutureResult.from_result(Success(1)), 22 | FutureResult.from_result(Failure(1)), 23 | FutureResult.from_future(Future.from_value(1)), 24 | FutureResult.from_failed_future(Future.from_value(1)), 25 | FutureResult.from_typecast(Future.from_value(Success(1))), 26 | ] 27 | for container in containers: 28 | with subtests.test(container=container): 29 | result_inst = await container 30 | assert result_inst._inner_value._inner_value == 1 # noqa: SLF001 31 | -------------------------------------------------------------------------------- /tests/test_io/test_io_container/test_io.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.io import IO, IOFailure, IOResult, IOSuccess 4 | 5 | 6 | def test_io_map(): 7 | """Ensures that IO container supports ``.map()`` method.""" 8 | io: IO[float] = IO(1).map( 9 | lambda number: number / 2, 10 | ) 11 | 12 | assert io == IO(0.5) 13 | 14 | 15 | def test_io_bind(): 16 | """Ensures that IO container supports ``.bind()`` method.""" 17 | io: IO[int] = IO('1').bind( 18 | lambda number: IO(int(number)), 19 | ) 20 | 21 | assert io == IO(1) 22 | 23 | 24 | def test_io_str(): 25 | """Ensures that IO container supports str cast.""" 26 | assert str(IO([])) == '' 27 | 28 | 29 | @pytest.mark.parametrize( 30 | 'container', 31 | [ 32 | IOSuccess(1), 33 | IOFailure(1), 34 | ], 35 | ) 36 | def test_io_typecast_reverse(container): 37 | """Ensures that IO can be casted to IOResult and back.""" 38 | assert IO.from_ioresult(container) == IO.from_ioresult( 39 | IOResult.from_typecast(IO.from_ioresult(container)), 40 | ) 41 | -------------------------------------------------------------------------------- /tests/test_io/test_io_container/test_io_equality.py: -------------------------------------------------------------------------------- 1 | from returns.io import IO 2 | 3 | 4 | def test_equals(): 5 | """Ensures that ``.equals`` method works correctly.""" 6 | assert IO(1).equals(IO(1)) 7 | assert IO(1).equals(IO.from_value(1)) 8 | 9 | 10 | def test_not_equals(): 11 | """Ensures that ``.equals`` method works correctly.""" 12 | assert not IO(1).equals(IO('a')) 13 | 14 | 15 | def test_equality(): 16 | """Ensures that containers can be compared.""" 17 | assert IO(1) == IO(1) 18 | assert str(IO(2)) == '' 19 | assert hash(IO((1, 2, 3))) 20 | 21 | 22 | def test_nonequality(): 23 | """Ensures that containers are not compared to regular values.""" 24 | assert IO(1) != 1 25 | assert IO(2) is not IO(2) 26 | assert IO('a') != IO('b') 27 | -------------------------------------------------------------------------------- /tests/test_io/test_io_container/test_io_functions/test_impure.py: -------------------------------------------------------------------------------- 1 | from returns.io import IO, impure 2 | 3 | 4 | def _fake_impure_function(some_param: int) -> int: 5 | return some_param 6 | 7 | 8 | def test_impure(): 9 | """Ensures that impure returns IO container.""" 10 | impure_result = impure(_fake_impure_function)(1) 11 | assert isinstance(impure_result, IO) 12 | assert impure_result == IO(1) 13 | -------------------------------------------------------------------------------- /tests/test_io/test_io_container/test_io_pickle.py: -------------------------------------------------------------------------------- 1 | from returns.io import IO 2 | 3 | 4 | def test_io_pickle(): 5 | """Tests how pickle protocol works for containers.""" 6 | assert IO(1).__getstate__() == {'container_value': 1} 7 | 8 | 9 | def test_io_pickle_restore(): 10 | """Ensures that object can be restored.""" 11 | container = IO(2) 12 | container.__setstate__({'container_value': 1}) 13 | assert container == IO(1) 14 | -------------------------------------------------------------------------------- /tests/test_io/test_ioresult_container/test_ioresult_equals.py: -------------------------------------------------------------------------------- 1 | from returns.io import IOFailure, IOSuccess 2 | 3 | 4 | def test_equals(): 5 | """Ensures that ``.equals`` method works correctly.""" 6 | inner_value = 1 7 | 8 | assert IOSuccess(inner_value).equals(IOSuccess(inner_value)) 9 | assert IOFailure(inner_value).equals(IOFailure(inner_value)) 10 | 11 | 12 | def test_not_equals(): 13 | """Ensures that ``.equals`` method works correctly.""" 14 | inner_value = 1 15 | 16 | assert not IOSuccess(inner_value).equals(IOFailure(inner_value)) 17 | assert not IOSuccess(inner_value).equals(IOSuccess(0)) 18 | assert not IOFailure(inner_value).equals(IOSuccess(inner_value)) 19 | assert not IOFailure(inner_value).equals(IOFailure(0)) 20 | -------------------------------------------------------------------------------- /tests/test_io/test_ioresult_container/test_ioresult_functions/test_impure_safe.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.io import IOSuccess, impure_safe 4 | 5 | 6 | @impure_safe 7 | def _function(number: int) -> float: 8 | return number / number 9 | 10 | 11 | @impure_safe(exceptions=(ZeroDivisionError,)) 12 | def _function_two(number: int | str) -> float: 13 | assert isinstance(number, int) 14 | return number / number 15 | 16 | 17 | @impure_safe((ZeroDivisionError,)) # no name 18 | def _function_three(number: int | str) -> float: 19 | assert isinstance(number, int) 20 | return number / number 21 | 22 | 23 | def test_safe_iosuccess(): 24 | """Ensures that safe decorator works correctly for IOSuccess case.""" 25 | assert _function(1) == IOSuccess(1.0) 26 | 27 | 28 | def test_safe_iofailure(): 29 | """Ensures that safe decorator works correctly for IOFailure case.""" 30 | failed = _function(0) 31 | assert isinstance( 32 | failed.failure()._inner_value, # noqa: SLF001 33 | ZeroDivisionError, 34 | ) 35 | 36 | 37 | def test_safe_failure_with_expected_error(): 38 | """Ensures that safe decorator works correctly for Failure case.""" 39 | failed = _function_two(0) 40 | assert isinstance( 41 | failed.failure()._inner_value, # noqa: SLF001 42 | ZeroDivisionError, 43 | ) 44 | 45 | failed2 = _function_three(0) 46 | assert isinstance( 47 | failed2.failure()._inner_value, # noqa: SLF001 48 | ZeroDivisionError, 49 | ) 50 | 51 | 52 | def test_safe_failure_with_non_expected_error(): 53 | """Ensures that safe decorator works correctly for Failure case.""" 54 | with pytest.raises(AssertionError): 55 | _function_two('0') 56 | -------------------------------------------------------------------------------- /tests/test_io/test_ioresult_container/test_ioresult_map.py: -------------------------------------------------------------------------------- 1 | from returns.io import IOFailure, IOSuccess 2 | 3 | 4 | def test_map_iosuccess(): 5 | """Ensures that IOSuccess is mappable.""" 6 | assert IOSuccess(5).map(str) == IOSuccess('5') 7 | 8 | 9 | def test_alt_iofailure(): 10 | """Ensures that IOFailure is mappable.""" 11 | assert IOFailure(5).map(str) == IOFailure(5) 12 | assert IOFailure(5).alt(str) == IOFailure('5') 13 | 14 | 15 | def test_alt_iosuccess(): 16 | """Ensures that IOSuccess.alt is NoOp.""" 17 | assert IOSuccess(5).alt(str) == IOSuccess(5) 18 | -------------------------------------------------------------------------------- /tests/test_io/test_ioresult_container/test_ioresult_values.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.io import IO, IOFailure, IOSuccess 4 | from returns.primitives.exceptions import UnwrapFailedError 5 | 6 | 7 | def test_ioresult_value_or(): 8 | """Ensures that ``value_or`` works correctly.""" 9 | assert IOSuccess(1).value_or(0) == IO(1) 10 | assert IOFailure(1).value_or(0) == IO(0) 11 | 12 | 13 | def test_unwrap_iosuccess(): 14 | """Ensures that unwrap works for IOSuccess container.""" 15 | assert IOSuccess(5).unwrap() == IO(5) 16 | 17 | 18 | def test_unwrap_iofailure(): 19 | """Ensures that unwrap works for IOFailure container.""" 20 | with pytest.raises(UnwrapFailedError): 21 | IOFailure(5).unwrap() 22 | 23 | 24 | def test_unwrap_iofailure_with_exception(): 25 | """Ensures that unwrap raises from the original exception.""" 26 | expected_exception = ValueError('error') 27 | with pytest.raises(UnwrapFailedError) as excinfo: 28 | IOFailure(expected_exception).unwrap() 29 | 30 | assert 'ValueError: error' in str( 31 | excinfo.getrepr(), # noqa: WPS441 32 | ) 33 | 34 | 35 | def test_failure_iosuccess(): 36 | """Ensures that failure works for IOSuccess container.""" 37 | with pytest.raises(UnwrapFailedError): 38 | IOSuccess(5).failure() 39 | 40 | 41 | def test_failure_iofailure(): 42 | """Ensures that failure works for IOFailure container.""" 43 | assert IOFailure(5).failure() == IO(5) 44 | -------------------------------------------------------------------------------- /tests/test_io/test_ioresult_container/test_ioresulte_cast.py: -------------------------------------------------------------------------------- 1 | from returns.io import IOFailure, IOResult, IOResultE, IOSuccess 2 | from returns.pipeline import is_successful 3 | 4 | 5 | def _function(arg: int) -> IOResultE[float]: 6 | if arg == 0: 7 | return IOFailure(ZeroDivisionError('Divided by 0')) 8 | return IOSuccess(10 / arg) 9 | 10 | 11 | def test_ioresulte(): 12 | """Ensures that IOResultE correctly typecast.""" 13 | container: IOResult[float, Exception] = _function(1) 14 | assert container == IOSuccess(10.0) 15 | 16 | container = _function(0) 17 | assert is_successful(container) is False 18 | -------------------------------------------------------------------------------- /tests/test_laws.py: -------------------------------------------------------------------------------- 1 | from returns.context import ( 2 | Reader, 3 | ReaderFutureResult, 4 | ReaderIOResult, 5 | ReaderResult, 6 | ) 7 | from returns.contrib.hypothesis.laws import check_all_laws 8 | from returns.future import Future, FutureResult 9 | from returns.io import IO, IOResult 10 | from returns.maybe import Maybe 11 | from returns.result import Result 12 | 13 | check_all_laws(Maybe) 14 | check_all_laws(Result) 15 | 16 | check_all_laws(IO) 17 | check_all_laws(IOResult) 18 | 19 | check_all_laws(Future) 20 | check_all_laws(FutureResult) 21 | 22 | check_all_laws(Reader) 23 | check_all_laws(ReaderResult) 24 | check_all_laws(ReaderIOResult) 25 | check_all_laws(ReaderFutureResult) 26 | -------------------------------------------------------------------------------- /tests/test_maybe/test_maybe_bind.py: -------------------------------------------------------------------------------- 1 | from returns.maybe import Maybe, Nothing, Some 2 | 3 | 4 | def test_bind_some(): 5 | """Ensures that bind works correctly.""" 6 | 7 | def factory(inner_value: int) -> Maybe[int]: 8 | return Some(inner_value * 2) 9 | 10 | input_value = 5 11 | bound = Some(input_value).bind(factory) 12 | 13 | assert bound == factory(input_value) 14 | assert str(bound) == '' 15 | 16 | 17 | def test_bind_optional(): 18 | """Ensures that bind_optional works correctly.""" 19 | 20 | def factory(inner_value: int) -> int | None: 21 | return inner_value or None 22 | 23 | assert Some(1).bind_optional(factory) == Some(1) 24 | assert Some(0).bind_optional(factory) == Nothing 25 | assert Nothing.bind_optional(factory) == Nothing 26 | -------------------------------------------------------------------------------- /tests/test_maybe/test_maybe_functions/test_maybe_decorator.py: -------------------------------------------------------------------------------- 1 | from returns.maybe import Nothing, Some, maybe 2 | 3 | 4 | @maybe 5 | def _function(hashmap: dict[str, str], key: str) -> str | None: 6 | return hashmap.get(key) 7 | 8 | 9 | def test_maybe_some(): 10 | """Ensures that maybe decorator works correctly for some case.""" 11 | assert _function({'a': 'b'}, 'a') == Some('b') 12 | 13 | 14 | def test_maybe_nothing(): 15 | """Ensures that maybe decorator works correctly for nothing case.""" 16 | assert _function({'a': 'b'}, 'c') == Nothing 17 | -------------------------------------------------------------------------------- /tests/test_maybe/test_maybe_unwrap.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.maybe import Nothing, Some 4 | from returns.primitives.exceptions import UnwrapFailedError 5 | 6 | 7 | def test_unwrap_success(): 8 | """Ensures that unwrap works for Some container.""" 9 | assert Some(5).unwrap() == 5 10 | 11 | 12 | def test_unwrap_failure(): 13 | """Ensures that unwrap works for Nothing container.""" 14 | with pytest.raises(UnwrapFailedError): 15 | assert Nothing.unwrap() 16 | -------------------------------------------------------------------------------- /tests/test_maybe/test_nothing_singleton.py: -------------------------------------------------------------------------------- 1 | from returns.maybe import _Nothing # noqa: PLC2701 2 | 3 | 4 | def test_nothing_singleton(): 5 | """Ensures `_Nothing` is a singleton.""" 6 | assert _Nothing() is _Nothing() 7 | -------------------------------------------------------------------------------- /tests/test_methods/test_partition.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.io import IO, IOResult 4 | from returns.maybe import Nothing, Some 5 | from returns.methods import partition 6 | from returns.result import Failure, Success 7 | 8 | 9 | @pytest.mark.parametrize( 10 | ('containers', 'expected'), 11 | [ 12 | ( 13 | (Success(1), Success(2), Failure(None), Success(3)), 14 | ([1, 2, 3], [None]), 15 | ), 16 | ( 17 | ( 18 | IOResult.from_value(1), 19 | IOResult.from_failure(2), 20 | IOResult.from_value(3), 21 | IOResult.from_failure(4), 22 | ), 23 | ([IO(1), IO(3)], [IO(2), IO(4)]), # noqa: WPS221 24 | ), 25 | ( 26 | (Some(1), Some(2), Nothing), 27 | ([1, 2], [None]), 28 | ), 29 | ((), ([], [])), 30 | ], 31 | ) 32 | def test_partition(containers, expected): 33 | """Test partition function.""" 34 | assert partition(containers) == expected 35 | -------------------------------------------------------------------------------- /tests/test_pipeline/test_is_successful.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.io import IOFailure, IOSuccess 4 | from returns.maybe import Nothing, Some 5 | from returns.pipeline import is_successful 6 | from returns.result import Failure, Success 7 | 8 | 9 | @pytest.mark.parametrize( 10 | ('container', 'correct_result'), 11 | [ 12 | (Success('a'), True), 13 | (Failure('a'), False), 14 | (IOSuccess('a'), True), 15 | (IOFailure('a'), False), 16 | (Some('a'), True), 17 | (Some(None), True), 18 | (Nothing, False), 19 | ], 20 | ) 21 | def test_is_successful(container, correct_result): 22 | """Ensures that successful state works correctly.""" 23 | assert is_successful(container) is correct_result 24 | -------------------------------------------------------------------------------- /tests/test_primitives/test_container/test_base_container/test_pickle.py: -------------------------------------------------------------------------------- 1 | import pickle # noqa: S403 2 | from typing import Any 3 | 4 | from hypothesis import example, given 5 | from hypothesis import strategies as st 6 | 7 | from returns.primitives.container import BaseContainer 8 | 9 | 10 | class _CustomClass: 11 | def __init__(self, inner_value: Any) -> None: 12 | self.inner_value = inner_value 13 | 14 | def __eq__(self, other: object) -> bool: 15 | return ( 16 | type(other) is type(self) # noqa: WPS516 17 | and self.inner_value == other.inner_value # type: ignore[attr-defined] 18 | ) 19 | 20 | def __hash__(self) -> int: 21 | return hash(self.inner_value) 22 | 23 | 24 | @given( 25 | st.one_of( 26 | st.integers(), 27 | st.floats(allow_nan=False), 28 | st.text(), 29 | st.booleans(), 30 | st.lists(st.text()), 31 | st.dictionaries(st.text(), st.integers()), 32 | st.builds(_CustomClass, st.text()), 33 | ), 34 | ) 35 | @example(None) 36 | def test_pickle(container_value: Any): 37 | """Ensures custom pickle protocol works as expected.""" 38 | container = BaseContainer(container_value) 39 | assert pickle.loads(pickle.dumps(container)) == container # noqa: S301 40 | -------------------------------------------------------------------------------- /tests/test_primitives/test_container/test_base_container/test_pickle_backward_deserialization.py: -------------------------------------------------------------------------------- 1 | import pickle # noqa: S403 2 | 3 | from returns.primitives.container import BaseContainer 4 | 5 | 6 | def test_pickle_backward_deserialization(): 7 | """Test that BaseContainer can be deserialized from 0.19.0 and earlier.""" 8 | # BaseContainer(1) serialized as of 0.19.0 9 | serialized_container = ( 10 | b'\x80\x04\x958\x00\x00\x00\x00\x00\x00\x00\x8c\x1c' 11 | + b'returns.primitives.container\x94\x8c\rBaseContainer' 12 | + b'\x94\x93\x94)\x81\x94K\x01b.' 13 | ) 14 | assert pickle.loads(serialized_container) == BaseContainer(1) # noqa: S301 15 | -------------------------------------------------------------------------------- /tests/test_primitives/test_exceptions/test_pickle_unwrap_failed_error.py: -------------------------------------------------------------------------------- 1 | import pickle # noqa: S403 2 | 3 | from returns.maybe import Nothing 4 | from returns.primitives.exceptions import UnwrapFailedError 5 | from returns.result import Failure 6 | 7 | 8 | def test_pickle_unwrap_failed_error_from_maybe(): 9 | """Ensures that UnwrapFailedError with Maybe can be pickled.""" 10 | serialized = None 11 | try: 12 | Nothing.unwrap() # This will raise UnwrapFailedError 13 | except UnwrapFailedError as error: 14 | serialized = pickle.dumps(error) 15 | 16 | deserialized_error = pickle.loads(serialized) # noqa: S301 17 | assert deserialized_error.halted_container == Nothing 18 | 19 | 20 | def test_pickle_unwrap_failed_error_from_result(): 21 | """Ensures that UnwrapFailedError with Result can be pickled.""" 22 | serialized = None 23 | try: 24 | Failure('error').unwrap() # This will raise UnwrapFailedError 25 | except UnwrapFailedError as error: 26 | serialized = pickle.dumps(error) 27 | 28 | deserialized_error = pickle.loads(serialized) # noqa: S301 29 | assert deserialized_error.halted_container == Failure('error') 30 | -------------------------------------------------------------------------------- /tests/test_result/test_result_error.py: -------------------------------------------------------------------------------- 1 | from returns.result import Failure, ResultE, Success 2 | 3 | 4 | def test_result_error_success(): 5 | """Ensures that ResultE can be typecasted to success.""" 6 | container: ResultE[int] = Success(1) 7 | assert container.unwrap() == 1 8 | 9 | 10 | def test_result_error_failure(): 11 | """Ensures that ResultE can be typecasted to failure.""" 12 | container: ResultE[int] = Failure(ValueError('1')) 13 | assert str(container.failure()) == '1' 14 | -------------------------------------------------------------------------------- /tests/test_result/test_result_failure.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.primitives.exceptions import UnwrapFailedError 4 | from returns.result import Failure, Success 5 | 6 | 7 | def test_unwrap_success(): 8 | """Ensures that unwrap works for Success container.""" 9 | with pytest.raises(UnwrapFailedError): 10 | assert Success(5).failure() 11 | 12 | 13 | def test_unwrap_failure(): 14 | """Ensures that unwrap works for Failure container.""" 15 | assert Failure(5).failure() == 5 16 | -------------------------------------------------------------------------------- /tests/test_result/test_result_functions/test_safe.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.result import Success, safe 4 | 5 | 6 | @safe 7 | def _function(number: int) -> float: 8 | return number / number 9 | 10 | 11 | @safe(exceptions=(ZeroDivisionError,)) 12 | def _function_two(number: int | str) -> float: 13 | assert isinstance(number, int) 14 | return number / number 15 | 16 | 17 | @safe((ZeroDivisionError,)) # no name 18 | def _function_three(number: int | str) -> float: 19 | assert isinstance(number, int) 20 | return number / number 21 | 22 | 23 | def test_safe_success(): 24 | """Ensures that safe decorator works correctly for Success case.""" 25 | assert _function(1) == Success(1.0) 26 | 27 | 28 | def test_safe_failure(): 29 | """Ensures that safe decorator works correctly for Failure case.""" 30 | failed = _function(0) 31 | assert isinstance(failed.failure(), ZeroDivisionError) 32 | 33 | 34 | def test_safe_failure_with_expected_error(): 35 | """Ensures that safe decorator works correctly for Failure case.""" 36 | failed = _function_two(0) 37 | assert isinstance(failed.failure(), ZeroDivisionError) 38 | 39 | failed2 = _function_three(0) 40 | assert isinstance(failed2.failure(), ZeroDivisionError) 41 | 42 | 43 | def test_safe_failure_with_non_expected_error(): 44 | """Ensures that safe decorator works correctly for Failure case.""" 45 | with pytest.raises(AssertionError): 46 | _function_two('0') 47 | -------------------------------------------------------------------------------- /tests/test_result/test_result_map.py: -------------------------------------------------------------------------------- 1 | from returns.result import Failure, Success 2 | 3 | 4 | def test_map_success(): 5 | """Ensures that Success is mappable.""" 6 | assert Success(5).map(str) == Success('5') 7 | 8 | 9 | def test_alt_failure(): 10 | """Ensures that Failure is mappable.""" 11 | assert Failure(5).map(str) == Failure(5) 12 | assert Failure(5).alt(str) == Failure('5') 13 | 14 | 15 | def test_alt_success(): 16 | """Ensures that Success.alt is NoOp.""" 17 | assert Success(5).alt(str) == Success(5) 18 | -------------------------------------------------------------------------------- /tests/test_result/test_result_unwrap.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from returns.primitives.exceptions import UnwrapFailedError 4 | from returns.result import Failure, Success 5 | 6 | 7 | def test_unwrap_success(): 8 | """Ensures that unwrap works for Success container.""" 9 | assert Success(5).unwrap() == 5 10 | 11 | 12 | def test_unwrap_failure(): 13 | """Ensures that unwrap works for Failure container.""" 14 | with pytest.raises(UnwrapFailedError): 15 | assert Failure(5).unwrap() 16 | 17 | 18 | def test_unwrap_failure_with_exception(): 19 | """Ensures that unwrap raises from the original exception.""" 20 | expected_exception = ValueError('error') 21 | with pytest.raises(UnwrapFailedError) as excinfo: 22 | Failure(expected_exception).unwrap() 23 | 24 | assert 'ValueError: error' in str( 25 | excinfo.getrepr(), # noqa: WPS441 26 | ) 27 | -------------------------------------------------------------------------------- /tests/test_result/test_result_value_or.py: -------------------------------------------------------------------------------- 1 | from returns.result import Failure, Success 2 | 3 | 4 | def test_success_value(): 5 | """Ensures that value is fetch correctly from the Success.""" 6 | bound = Success(5).value_or(None) 7 | 8 | assert bound == 5 9 | 10 | 11 | def test_failure_value(): 12 | """Ensures that value is fetch correctly from the Failure.""" 13 | bound = Failure(1).value_or(default_value=None) 14 | 15 | assert bound is None 16 | -------------------------------------------------------------------------------- /tests/test_trampolines/test_trampoline_decorator.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from collections.abc import Callable, Iterator 3 | 4 | import pytest 5 | 6 | from returns.trampolines import Trampoline, trampoline 7 | 8 | 9 | @trampoline 10 | def _accumulate( 11 | numbers: Iterator[int], 12 | acc: int = 0, 13 | ) -> int | Trampoline[int]: 14 | number = next(numbers, None) 15 | if number is None: 16 | return acc 17 | return Trampoline(_accumulate, numbers, acc + number) 18 | 19 | 20 | @trampoline 21 | def _with_func_kwarg( 22 | numbers: Iterator[int], 23 | func: int = 0, # we need this name to match `Trampoline` constructor 24 | ) -> int | Trampoline[int]: 25 | number = next(numbers, None) 26 | if number is None: 27 | return func 28 | return Trampoline(_with_func_kwarg, numbers, func=func + number) 29 | 30 | 31 | @pytest.mark.parametrize( 32 | 'trampoline_func', 33 | [ 34 | _accumulate, 35 | _with_func_kwarg, 36 | ], 37 | ) 38 | @pytest.mark.parametrize( 39 | 'given_range', 40 | [ 41 | range(0), 42 | range(1), 43 | range(2), 44 | range(5), 45 | range(sys.getrecursionlimit()), 46 | range(sys.getrecursionlimit() + 1), 47 | ], 48 | ) 49 | def test_recursion_limit( 50 | trampoline_func: Callable[[Iterator[int]], int], 51 | given_range: range, 52 | ) -> None: 53 | """Test that accumulation is correct and no ``RecursionError`` happens.""" 54 | accumulated = trampoline_func(iter(given_range)) 55 | 56 | assert accumulated == sum(given_range) 57 | -------------------------------------------------------------------------------- /tests/test_unsafe/test_unsafe_perform_io.py: -------------------------------------------------------------------------------- 1 | from returns.io import IO 2 | from returns.unsafe import unsafe_perform_io 3 | 4 | 5 | def test_unsafe_perform_io(): 6 | """Ensures that unsafe_perform_io returns the object itself.""" 7 | id_object = object() 8 | assert unsafe_perform_io(IO(id_object)) is id_object 9 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context/test_context.yml: -------------------------------------------------------------------------------- 1 | - case: context_ask1 2 | disable_cache: false 3 | main: | 4 | from returns.context import RequiresContext 5 | 6 | reveal_type(RequiresContext.ask()) # N: Revealed type is "returns.context.requires_context.RequiresContext[Never, Never]" 7 | 8 | 9 | - case: context_ask2 10 | disable_cache: false 11 | main: | 12 | from returns.context import RequiresContext 13 | 14 | reveal_type(RequiresContext[int, str].ask()) # N: Revealed type is "returns.context.requires_context.RequiresContext[builtins.str, builtins.str]" 15 | 16 | 17 | - case: requires_context_from_value 18 | disable_cache: false 19 | main: | 20 | from returns.context import RequiresContext 21 | 22 | reveal_type(RequiresContext.from_value(1)) # N: Revealed type is "returns.context.requires_context.RequiresContext[builtins.int, Any]" 23 | 24 | 25 | - case: requires_context_from_context 26 | disable_cache: false 27 | main: | 28 | from returns.context import RequiresContext 29 | 30 | x: RequiresContext[int, str] 31 | reveal_type(RequiresContext.from_context(x)) # N: Revealed type is "returns.context.requires_context.RequiresContext[builtins.int, builtins.str]" 32 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context/test_requires_context_typecast.yml: -------------------------------------------------------------------------------- 1 | - case: requires_context_from_requires_context_ioresult 2 | disable_cache: true 3 | main: | 4 | from returns.context import RequiresContext 5 | from returns.context import RequiresContextIOResult 6 | 7 | x: RequiresContextIOResult[int, float, str] 8 | 9 | reveal_type(RequiresContext.from_requires_context_ioresult(x)) # N: Revealed type is "returns.context.requires_context.RequiresContext[returns.io.IOResult[builtins.int, builtins.float], builtins.str]" 10 | 11 | 12 | - case: requires_context_from_requires_context_result 13 | disable_cache: true 14 | main: | 15 | from returns.context import RequiresContext 16 | from returns.context import RequiresContextResult 17 | 18 | x: RequiresContextResult[int, float, str] 19 | 20 | reveal_type(RequiresContext.from_requires_context_result(x)) # N: Revealed type is "returns.context.requires_context.RequiresContext[returns.result.Result[builtins.int, builtins.float], builtins.str]" 21 | 22 | 23 | - case: requires_context_from_requires_context_future_result 24 | disable_cache: true 25 | main: | 26 | from returns.context import RequiresContext 27 | from returns.context import RequiresContextFutureResult 28 | 29 | x: RequiresContextFutureResult[int, float, str] 30 | 31 | reveal_type(RequiresContext.from_requires_context_future_result(x)) # N: Revealed type is "returns.context.requires_context.RequiresContext[returns.future.FutureResult[builtins.int, builtins.float], builtins.str]" 32 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_future_result/test_context_future_result.yml: -------------------------------------------------------------------------------- 1 | - case: context_result_future_ask1 2 | disable_cache: false 3 | main: | 4 | from returns.context import RequiresContextFutureResult 5 | 6 | reveal_type(RequiresContextFutureResult.ask()) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[Never, Never, Never]" 7 | 8 | 9 | - case: context_result_future_ask2 10 | disable_cache: false 11 | main: | 12 | from returns.context import RequiresContextFutureResult 13 | 14 | reveal_type(RequiresContextFutureResult[int, bool, str].ask()) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.str, builtins.bool, builtins.str]" 15 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_future_result/test_requires_context_future_result_aliases.yml: -------------------------------------------------------------------------------- 1 | - case: requires_context_future_result_aliases 2 | disable_cache: false 3 | main: | 4 | from returns.context import ( 5 | RequiresContextFutureResult, 6 | RequiresContextFutureResultE, 7 | ReaderFutureResult, 8 | ReaderFutureResultE, 9 | ) 10 | 11 | x: RequiresContextFutureResult[int, Exception, str] 12 | 13 | x1: RequiresContextFutureResultE[int, str] = x 14 | x2: ReaderFutureResult[int, Exception, str] = x 15 | x3: ReaderFutureResultE[int, str] = x 16 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_future_result/test_requires_context_future_result_cast.yml: -------------------------------------------------------------------------------- 1 | - case: requires_context_future_result_success_cast 2 | disable_cache: false 3 | main: | 4 | from returns.context import RequiresContextFutureResult 5 | 6 | first: RequiresContextFutureResult[object, Exception, str] = RequiresContextFutureResult.from_value(1) 7 | reveal_type(first) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.object, builtins.Exception, builtins.str]" 8 | 9 | 10 | - case: requires_context_future_result_failure_cast 11 | disable_cache: false 12 | main: | 13 | from returns.context import RequiresContextFutureResult 14 | 15 | first: RequiresContextFutureResult[object, Exception, str] = RequiresContextFutureResult.from_failure(TypeError()) 16 | reveal_type(first) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.object, builtins.Exception, builtins.str]" 17 | 18 | 19 | - case: requires_context_future_result_env_cast 20 | disable_cache: false 21 | main: | 22 | from returns.context import RequiresContextFutureResult 23 | 24 | first: RequiresContextFutureResult[object, Exception, object] 25 | second: RequiresContextFutureResult[object, Exception, str] = first 26 | 27 | reveal_type(second) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.object, builtins.Exception, builtins.str]" 28 | 29 | 30 | - case: requires_context_future_result_wrong_cast 31 | disable_cache: false 32 | main: | 33 | from returns.context import RequiresContextFutureResult 34 | 35 | first: RequiresContextFutureResult[ValueError, TypeError, IndexError] 36 | second: RequiresContextFutureResult[Exception, Exception, Exception] = first 37 | out: | 38 | main:4: error: Incompatible types in assignment (expression has type "RequiresContextFutureResult[ValueError, TypeError, IndexError]", variable has type "RequiresContextFutureResult[Exception, Exception, Exception]") [assignment] 39 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_ioresult/test_context_ioresult.yml: -------------------------------------------------------------------------------- 1 | - case: context_result_io_ask1 2 | disable_cache: false 3 | main: | 4 | from returns.context import RequiresContextIOResult 5 | 6 | reveal_type(RequiresContextIOResult.ask()) # N: Revealed type is "returns.context.requires_context_ioresult.RequiresContextIOResult[Never, Never, Never]" 7 | 8 | 9 | - case: context_result_io_ask2 10 | disable_cache: false 11 | main: | 12 | from returns.context import RequiresContextIOResult 13 | 14 | reveal_type(RequiresContextIOResult[int, bool, str].ask()) # N: Revealed type is "returns.context.requires_context_ioresult.RequiresContextIOResult[builtins.str, builtins.bool, builtins.str]" 15 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_ioresult/test_requires_context_ioresult_aliases.yml: -------------------------------------------------------------------------------- 1 | - case: requires_context_ioresult_aliases 2 | disable_cache: false 3 | main: | 4 | from returns.context import ( 5 | RequiresContextIOResult, 6 | RequiresContextIOResultE, 7 | ReaderIOResult, 8 | ReaderIOResultE, 9 | ) 10 | 11 | x: RequiresContextIOResult[int, Exception, str] 12 | 13 | x1: RequiresContextIOResultE[int, str] = x 14 | x2: ReaderIOResult[int, Exception, str] = x 15 | x3: ReaderIOResultE[int, str] = x 16 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_ioresult/test_requires_context_ioresult_cast.yml: -------------------------------------------------------------------------------- 1 | - case: requires_context_ioresult_success_cast 2 | disable_cache: false 3 | main: | 4 | from returns.context import RequiresContextIOResult 5 | 6 | first: RequiresContextIOResult[object, Exception, str] = RequiresContextIOResult.from_value(1) 7 | reveal_type(first) # N: Revealed type is "returns.context.requires_context_ioresult.RequiresContextIOResult[builtins.object, builtins.Exception, builtins.str]" 8 | 9 | 10 | - case: requires_context_ioresult_failure_cast 11 | disable_cache: false 12 | main: | 13 | from returns.context import RequiresContextIOResult 14 | 15 | first: RequiresContextIOResult[object, Exception, str] = RequiresContextIOResult.from_failure(TypeError()) 16 | reveal_type(first) # N: Revealed type is "returns.context.requires_context_ioresult.RequiresContextIOResult[builtins.object, builtins.Exception, builtins.str]" 17 | 18 | 19 | - case: requires_context_ioresult_env_cast 20 | disable_cache: false 21 | main: | 22 | from returns.context import RequiresContextIOResult 23 | 24 | first: RequiresContextIOResult[object, Exception, object] 25 | second: RequiresContextIOResult[object, Exception, str] = first 26 | 27 | reveal_type(second) # N: Revealed type is "returns.context.requires_context_ioresult.RequiresContextIOResult[builtins.object, builtins.Exception, builtins.str]" 28 | 29 | 30 | - case: requires_context_ioresult_wrong_cast 31 | disable_cache: false 32 | main: | 33 | from returns.context import RequiresContextIOResult 34 | 35 | first: RequiresContextIOResult[ValueError, TypeError, IndexError] 36 | second: RequiresContextIOResult[Exception, Exception, Exception] = first 37 | out: | 38 | main:4: error: Incompatible types in assignment (expression has type "RequiresContextIOResult[ValueError, TypeError, IndexError]", variable has type "RequiresContextIOResult[Exception, Exception, Exception]") [assignment] 39 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_result/test_context_result.yml: -------------------------------------------------------------------------------- 1 | - case: context_ask1 2 | disable_cache: false 3 | main: | 4 | from returns.context import RequiresContextResult 5 | 6 | reveal_type(RequiresContextResult.ask()) # N: Revealed type is "returns.context.requires_context_result.RequiresContextResult[Never, Never, Never]" 7 | 8 | 9 | - case: context_ask2 10 | disable_cache: false 11 | main: | 12 | from returns.context import RequiresContextResult 13 | 14 | reveal_type(RequiresContextResult[int, bool, str].ask()) # N: Revealed type is "returns.context.requires_context_result.RequiresContextResult[builtins.str, builtins.bool, builtins.str]" 15 | -------------------------------------------------------------------------------- /typesafety/test_context/test_requires_context_result/test_requires_context_cast.yml: -------------------------------------------------------------------------------- 1 | - case: requires_context_result_success_cast 2 | disable_cache: false 3 | main: | 4 | from returns.context import RequiresContextResult 5 | 6 | first: RequiresContextResult[object, Exception, str] = RequiresContextResult.from_value(1) 7 | reveal_type(first) # N: Revealed type is "returns.context.requires_context_result.RequiresContextResult[builtins.object, builtins.Exception, builtins.str]" 8 | 9 | 10 | - case: requires_context_result_failure_cast 11 | disable_cache: false 12 | main: | 13 | from returns.context import RequiresContextResult 14 | 15 | first: RequiresContextResult[object, Exception, str] = RequiresContextResult.from_failure(TypeError()) 16 | reveal_type(first) # N: Revealed type is "returns.context.requires_context_result.RequiresContextResult[builtins.object, builtins.Exception, builtins.str]" 17 | 18 | 19 | - case: requires_context_result_env_cast 20 | disable_cache: false 21 | main: | 22 | from returns.context import RequiresContextResult 23 | 24 | first: RequiresContextResult[object, Exception, object] 25 | second: RequiresContextResult[object, Exception, str] = first 26 | 27 | reveal_type(second) # N: Revealed type is "returns.context.requires_context_result.RequiresContextResult[builtins.object, builtins.Exception, builtins.str]" 28 | 29 | 30 | - case: requires_context_result_wrong_cast 31 | disable_cache: false 32 | main: | 33 | from returns.context import RequiresContextResult 34 | 35 | first: RequiresContextResult[ValueError, TypeError, IndexError] 36 | second: RequiresContextResult[Exception, Exception, Exception] = first 37 | out: | 38 | main:4: error: Incompatible types in assignment (expression has type "RequiresContextResult[ValueError, TypeError, IndexError]", variable has type "RequiresContextResult[Exception, Exception, Exception]") [assignment] 39 | -------------------------------------------------------------------------------- /typesafety/test_converters/test_maybe_to_result.yml: -------------------------------------------------------------------------------- 1 | - case: maybe_to_result 2 | disable_cache: false 3 | main: | 4 | from returns.converters import maybe_to_result 5 | from returns.maybe import Maybe 6 | 7 | reveal_type(maybe_to_result(Maybe.from_value(1))) # N: Revealed type is "returns.result.Result[builtins.int, None]" 8 | 9 | 10 | - case: maybe_to_result_default_error 11 | disable_cache: false 12 | main: | 13 | from returns.converters import maybe_to_result 14 | from returns.maybe import Maybe 15 | 16 | reveal_type(maybe_to_result(Maybe.from_value(1), 'a')) # N: Revealed type is "returns.result.Result[builtins.int, builtins.str]" 17 | -------------------------------------------------------------------------------- /typesafety/test_converters/test_result_to_maybe.yml: -------------------------------------------------------------------------------- 1 | - case: result_to_maybe 2 | disable_cache: false 3 | main: | 4 | from returns.converters import result_to_maybe 5 | from returns.result import Result 6 | 7 | def returns_result() -> Result[int, str]: 8 | ... 9 | 10 | reveal_type(result_to_maybe(returns_result())) # N: Revealed type is "returns.maybe.Maybe[builtins.int]" 11 | -------------------------------------------------------------------------------- /typesafety/test_curry/test_curry/test_curry_args_kwargs.yml: -------------------------------------------------------------------------------- 1 | - case: curry_args 2 | disable_cache: false 3 | main: | 4 | from returns.curry import curry 5 | 6 | @curry 7 | def zero(*args) -> str: 8 | ... 9 | 10 | reveal_type(zero) # N: Revealed type is "Any" 11 | 12 | 13 | - case: curry_kwargs 14 | disable_cache: false 15 | main: | 16 | from returns.curry import curry 17 | 18 | @curry 19 | def zero(**kwargs) -> str: 20 | ... 21 | 22 | reveal_type(zero) # N: Revealed type is "Any" 23 | 24 | 25 | - case: curry_args_kwargs 26 | disable_cache: false 27 | main: | 28 | from returns.curry import curry 29 | 30 | @curry 31 | def zero(*args, **kwargs) -> str: 32 | ... 33 | 34 | reveal_type(zero) # N: Revealed type is "Any" 35 | -------------------------------------------------------------------------------- /typesafety/test_examples/test_your_container/test_pair4_def.yml: -------------------------------------------------------------------------------- 1 | - case: test_pair_type 2 | disable_cache: false 3 | env: 4 | # We only need this because we store this example in `tests/` 5 | # and not in our source code. Please, do not copy this line! 6 | - MYPYPATH=./tests/test_examples/test_your_container 7 | 8 | # TODO: remove this config after 9 | # mypy/typeshed/stdlib/unittest/mock.pyi:120: 10 | # error: Class cannot subclass "Any" (has type "Any") 11 | # is fixed. 12 | mypy_config: 13 | disallow_subclassing_any = False 14 | main: | 15 | # Let's import our `Pair` type we defined earlier: 16 | from test_pair4 import Pair 17 | 18 | reveal_type(Pair) 19 | 20 | def function(first: int, second: str) -> Pair[float, bool]: 21 | ... 22 | 23 | my_pair: Pair[int, str] = Pair.from_paired(1, 'a') 24 | reveal_type(my_pair.pair(function)) 25 | out: | 26 | main:4: note: Revealed type is "def [_FirstType, _SecondType] (inner_value: Tuple[_FirstType`1, _SecondType`2]) -> test_pair4.Pair[_FirstType`1, _SecondType`2]" 27 | main:10: note: Revealed type is "test_pair4.Pair[builtins.float, builtins.bool]" 28 | -------------------------------------------------------------------------------- /typesafety/test_examples/test_your_container/test_pair4_error.yml: -------------------------------------------------------------------------------- 1 | - case: test_pair_error 2 | disable_cache: false 3 | env: 4 | # We only need this because we store this example in `tests/` 5 | # and not in our source code. Please, do not copy this line! 6 | - MYPYPATH=./tests/test_examples/test_your_container 7 | 8 | # TODO: remove this config after 9 | # mypy/typeshed/stdlib/unittest/mock.pyi:120: 10 | # error: Class cannot subclass "Any" (has type "Any") 11 | # is fixed. 12 | mypy_config: 13 | disallow_subclassing_any = False 14 | main: | 15 | # Let's import our `Pair` type we defined earlier: 16 | from test_pair4 import Pair 17 | 18 | # Oups! This function has first and second types swapped! 19 | def function(first: str, second: int) -> Pair[float, bool]: 20 | ... 21 | 22 | my_pair = Pair.from_paired(1, 'a') 23 | my_pair.pair(function) # this should and will error 24 | out: | 25 | main:9: error: Argument 1 to "pair" of "Pair" has incompatible type "Callable[[str, int], Pair[float, bool]]"; expected "Callable[[int, str], KindN[Pair[Any, Any], float, bool, Any]]" [arg-type] 26 | -------------------------------------------------------------------------------- /typesafety/test_examples/test_your_container/test_pair4_reuse.yml: -------------------------------------------------------------------------------- 1 | - case: test_pair_map 2 | disable_cache: false 3 | env: 4 | # We only need this because we store this example in `tests/` 5 | # and not in our source code. Please, do not copy this line! 6 | - MYPYPATH=./tests/test_examples/test_your_container 7 | 8 | # TODO: remove this config after 9 | # mypy/typeshed/stdlib/unittest/mock.pyi:120: 10 | # error: Class cannot subclass "Any" (has type "Any") 11 | # is fixed. 12 | mypy_config: 13 | disallow_subclassing_any = False 14 | main: | 15 | from test_pair4 import Pair 16 | from returns.pointfree import map_ 17 | 18 | my_pair: Pair[int, int] = Pair.from_unpaired(1) 19 | reveal_type(my_pair.map(str)) 20 | reveal_type(map_(str)(my_pair)) 21 | out: | 22 | main:5: note: Revealed type is "test_pair4.Pair[builtins.str, builtins.int]" 23 | main:6: note: Revealed type is "test_pair4.Pair[builtins.str, builtins.int]" 24 | -------------------------------------------------------------------------------- /typesafety/test_functions/test_compose.yml: -------------------------------------------------------------------------------- 1 | - case: compose_two_correct_functions 2 | disable_cache: false 3 | main: | 4 | from returns.functions import compose 5 | 6 | def first(num: int) -> float: 7 | return float(num) 8 | 9 | def second(num: float) -> str: 10 | return str(num) 11 | 12 | reveal_type(compose(first, second)) # N: Revealed type is "def (builtins.int) -> builtins.str" 13 | 14 | 15 | - case: compose_two_wrong_functions 16 | main: | 17 | from returns.functions import compose 18 | 19 | def first(num: int) -> float: 20 | return float(num) 21 | 22 | def second(num: str) -> str: 23 | return str(num) 24 | 25 | reveal_type(compose(first, second)) 26 | out: | 27 | main:9: error: Cannot infer type argument 2 of "compose" [misc] 28 | main:9: note: Revealed type is "def (Any) -> Any" 29 | 30 | 31 | - case: compose_optional_functions 32 | mypy_config: 33 | no_implicit_optional = True 34 | main: | 35 | from returns.functions import compose 36 | 37 | def first(num: int = 1) -> float: 38 | return float(num) 39 | 40 | def second(num: float) -> str: 41 | return str(num) 42 | 43 | reveal_type(compose(first, second)) # N: Revealed type is "def (builtins.int) -> builtins.str" 44 | -------------------------------------------------------------------------------- /typesafety/test_functions/test_identity.yml: -------------------------------------------------------------------------------- 1 | - case: identity_function 2 | disable_cache: false 3 | main: | 4 | from returns.functions import identity 5 | 6 | reveal_type(identity(1)) # N: Revealed type is "builtins.int" 7 | -------------------------------------------------------------------------------- /typesafety/test_functions/test_not_.yml: -------------------------------------------------------------------------------- 1 | - case: function_with_one_argument 2 | disable_cache: false 3 | main: | 4 | from returns.functions import not_ 5 | 6 | def is_even(number: int) -> bool: 7 | return number % 2 == 0 8 | 9 | reveal_type(not_(is_even)) # N: Revealed type is "def (number: builtins.int) -> builtins.bool" 10 | 11 | 12 | - case: function_with_two_arguments 13 | main: | 14 | from returns.functions import not_ 15 | from typing import List 16 | 17 | def number_is_in_list(number: int, list_: List[int]) -> bool: 18 | return number in list_ 19 | 20 | reveal_type(not_(number_is_in_list)) # N: Revealed type is "def (number: builtins.int, list_: builtins.list[builtins.int]) -> builtins.bool" 21 | -------------------------------------------------------------------------------- /typesafety/test_functions/test_raise_exception.yml: -------------------------------------------------------------------------------- 1 | - case: raise_exception 2 | disable_cache: false 3 | main: | 4 | from returns.functions import raise_exception 5 | 6 | reveal_type(raise_exception(ValueError())) # N: Revealed type is "Never" 7 | -------------------------------------------------------------------------------- /typesafety/test_functions/test_tap.yml: -------------------------------------------------------------------------------- 1 | - case: tap_single_function 2 | disable_cache: false 3 | main: | 4 | from returns.functions import tap 5 | 6 | def first(num: int) -> float: 7 | return float(num) 8 | 9 | reveal_type(tap(first)) # N: Revealed type is "def (builtins.int) -> builtins.int" 10 | 11 | 12 | - case: untap_single_function 13 | disable_cache: false 14 | main: | 15 | from returns.functions import untap 16 | 17 | def first(num: int) -> float: 18 | return float(num) 19 | 20 | reveal_type(untap(first)) # N: Revealed type is "def (builtins.int)" 21 | reveal_type(untap(first)(1)) # N: Revealed type is "None" 22 | -------------------------------------------------------------------------------- /typesafety/test_future/test_future_container/test_asyncify_decorator.yml: -------------------------------------------------------------------------------- 1 | - case: asyncify_decorator_with_args 2 | disable_cache: false 3 | main: | 4 | from typing import Optional 5 | from returns.future import asyncify 6 | 7 | @asyncify 8 | def test( 9 | first: int, second: Optional[str] = None, *, kw: bool = True, 10 | ) -> int: 11 | return 1 12 | 13 | reveal_type(test) # N: Revealed type is "def (first: builtins.int, second: Union[builtins.str, None] =, *, kw: builtins.bool =) -> typing.Coroutine[Any, Any, builtins.int]" 14 | -------------------------------------------------------------------------------- /typesafety/test_future/test_future_container/test_do.yml: -------------------------------------------------------------------------------- 1 | - case: do_sync_error 2 | disable_cache: false 3 | main: | 4 | from returns.future import Future 5 | 6 | Future.do( 7 | x + 1 8 | for x in Future.from_value(1) 9 | ) 10 | out: | 11 | main:3: error: Argument 1 to "do" of "Future" has incompatible type "Generator[Any, None, None]"; expected "AsyncGenerator[Never, None]" [arg-type] 12 | main:5: error: "Future[int]" has no attribute "__iter__"; maybe "__aiter__"? (not iterable) [attr-defined] 13 | main:5: note: Maybe you forgot to use "await"? 14 | 15 | 16 | - case: do_types_missmatch 17 | disable_cache: false 18 | main: | 19 | from returns.future import Future, FutureSuccess 20 | 21 | Future.do( 22 | x + y 23 | async for x in FutureSuccess(1) # E: Invalid type supplied in do-notation: expected "returns.future.Future[Any]", got "returns.future.FutureResult[builtins.int, Any]" [misc] 24 | async for y in Future.from_value(2.5) 25 | ) 26 | 27 | 28 | - case: do_with_if 29 | disable_cache: false 30 | main: | 31 | from returns.future import Future 32 | 33 | Future.do( # E: Using "if" conditions inside a generator is not allowed [misc] 34 | x + y 35 | async for x in Future.from_value(1) 36 | async for y in Future.from_value(2.5) 37 | if y > 5 38 | ) 39 | 40 | 41 | - case: do_with_var 42 | disable_cache: false 43 | main: | 44 | from returns.future import Future 45 | 46 | x = ( 47 | x + y 48 | async for x in Future.from_value(1) 49 | async for y in Future.from_value(2.5) 50 | ) 51 | 52 | Future.do(x) # E: Literal generator expression is required, not a variable or function call [misc] 53 | -------------------------------------------------------------------------------- /typesafety/test_future/test_future_container/test_future_decorator.yml: -------------------------------------------------------------------------------- 1 | - case: future_decorator_with_args 2 | disable_cache: false 3 | main: | 4 | from typing import Optional 5 | from returns.future import future 6 | 7 | @future 8 | async def test( 9 | first: int, second: Optional[str] = None, *, kw: bool = True, 10 | ) -> int: 11 | ... 12 | 13 | reveal_type(test) # N: Revealed type is "def (first: builtins.int, second: Union[builtins.str, None] =, *, kw: builtins.bool =) -> returns.future.Future[builtins.int]" 14 | 15 | 16 | - case: future_composition 17 | disable_cache: false 18 | main: | 19 | from returns.future import future 20 | 21 | async def test(first: int) -> str: 22 | ... 23 | 24 | reveal_type(future(test)) # N: Revealed type is "def (first: builtins.int) -> returns.future.Future[builtins.str]" 25 | -------------------------------------------------------------------------------- /typesafety/test_future/test_future_container/test_future_typecast.yml: -------------------------------------------------------------------------------- 1 | - case: future_correct_cast 2 | disable_cache: false 3 | main: | 4 | from returns.future import Future 5 | 6 | first: Future[ValueError] 7 | second: Future[Exception] = first 8 | reveal_type(second) # N: Revealed type is "returns.future.Future[builtins.Exception]" 9 | 10 | 11 | - case: future_from_value 12 | disable_cache: false 13 | main: | 14 | from returns.future import Future 15 | 16 | reveal_type(Future.from_value(1)) # N: Revealed type is "returns.future.Future[builtins.int]" 17 | 18 | 19 | - case: future_from_io 20 | disable_cache: false 21 | main: | 22 | from returns.future import Future 23 | from returns.io import IO 24 | 25 | reveal_type(Future.from_io(IO(1))) # N: Revealed type is "returns.future.Future[builtins.int]" 26 | 27 | 28 | - case: future_from_downcast 29 | disable_cache: false 30 | main: | 31 | from returns.future import Future, FutureResult 32 | 33 | first: FutureResult[int, ValueError] 34 | reveal_type(Future.from_future_result(first)) # N: Revealed type is "returns.future.Future[returns.result.Result[builtins.int, builtins.ValueError]]" 35 | -------------------------------------------------------------------------------- /typesafety/test_interfaces/test_bimappable/test_bimappable_inheritance.yml: -------------------------------------------------------------------------------- 1 | - case: bimappable_inheritance_missing 2 | disable_cache: false 3 | main: | 4 | from typing import TypeVar, final 5 | from returns.interfaces.bimappable import BiMappable2 6 | from returns.primitives.hkt import SupportsKind2 7 | 8 | V = TypeVar('V') 9 | T = TypeVar('T') 10 | 11 | @final 12 | class MyClass(SupportsKind2['MyClass', V, T], BiMappable2[V, T]): 13 | ... 14 | out: | 15 | main:9: error: Final class main.MyClass has abstract attributes "alt", "map" [misc] 16 | -------------------------------------------------------------------------------- /typesafety/test_interfaces/test_container/test_inheritance.yml: -------------------------------------------------------------------------------- 1 | - case: container_inheritance_missing 2 | disable_cache: false 3 | main: | 4 | from typing import TypeVar 5 | from returns.interfaces.container import Container1 6 | from returns.primitives.hkt import SupportsKind1 7 | 8 | V = TypeVar('V') 9 | 10 | class MyClass(SupportsKind1['MyClass', V], Container1[V]): 11 | ... 12 | 13 | MyClass() 14 | out: | 15 | main:10: error: Cannot instantiate abstract class "MyClass" with abstract attributes "apply", "bind", "from_value" and "map" [abstract] 16 | -------------------------------------------------------------------------------- /typesafety/test_interfaces/test_failable/test_failable.yml: -------------------------------------------------------------------------------- 1 | - case: failable_inheritance_correct2 2 | disable_cache: false 3 | main: | 4 | from typing import TypeVar 5 | from returns.interfaces.failable import Failable2 6 | from returns.primitives.hkt import SupportsKind2 7 | 8 | _FirstType = TypeVar('_FirstType') 9 | _SecondType = TypeVar('_SecondType') 10 | 11 | class MyClass( 12 | SupportsKind2['MyClass', _FirstType, _SecondType], 13 | Failable2[_FirstType, _SecondType], 14 | ): 15 | ... 16 | 17 | 18 | - case: failable_inheritance_correct3 19 | disable_cache: false 20 | main: | 21 | from typing import TypeVar 22 | from returns.interfaces.failable import Failable3 23 | from returns.primitives.hkt import SupportsKind3 24 | 25 | _FirstType = TypeVar('_FirstType') 26 | _SecondType = TypeVar('_SecondType') 27 | _ThirdType = TypeVar('_ThirdType') 28 | 29 | class MyClass( 30 | SupportsKind3['MyClass', _FirstType, _SecondType, _ThirdType], 31 | Failable3[_FirstType, _SecondType, _ThirdType], 32 | ): 33 | ... 34 | 35 | 36 | - case: failable_inheritance_missing 37 | disable_cache: false 38 | main: | 39 | from typing import TypeVar, final 40 | from returns.interfaces.failable import Failable2 41 | from returns.primitives.hkt import SupportsKind2 42 | 43 | _FirstType = TypeVar('_FirstType') 44 | _SecondType = TypeVar('_SecondType') 45 | 46 | @final 47 | class MyClass( 48 | SupportsKind2['MyClass', _FirstType, _SecondType], 49 | Failable2[_FirstType, _SecondType], 50 | ): 51 | ... 52 | out: | 53 | main:9: error: Final class main.MyClass has abstract attributes "apply", "bind", "from_value", "lash", "map" [misc] 54 | -------------------------------------------------------------------------------- /typesafety/test_interfaces/test_failable/test_single_failable.yml: -------------------------------------------------------------------------------- 1 | - case: single_failable_inheritance_correct2 2 | disable_cache: false 3 | main: | 4 | from typing import TypeVar 5 | from returns.interfaces.failable import SingleFailable2 6 | from returns.primitives.hkt import SupportsKind2 7 | 8 | _FirstType = TypeVar('_FirstType') 9 | _SecondType = TypeVar('_SecondType') 10 | 11 | class MyClass( 12 | SupportsKind2['MyClass', _FirstType, _SecondType], 13 | SingleFailable2[_FirstType, _SecondType], 14 | ): 15 | ... 16 | 17 | 18 | - case: single_failable_inheretance_correct3 19 | disable_cache: false 20 | main: | 21 | from typing import TypeVar 22 | from returns.interfaces.failable import SingleFailable3 23 | from returns.primitives.hkt import SupportsKind3 24 | 25 | _FirstType = TypeVar('_FirstType') 26 | _SecondType = TypeVar('_SecondType') 27 | _ThirdType = TypeVar('_ThirdType') 28 | 29 | class MyClass( 30 | SupportsKind3['MyClass', _FirstType, _SecondType, _ThirdType], 31 | SingleFailable3[_FirstType, _SecondType, _ThirdType], 32 | ): 33 | ... 34 | 35 | 36 | - case: single_failable_inheritance_missing 37 | disable_cache: false 38 | main: | 39 | from typing import TypeVar, final 40 | from returns.interfaces.failable import SingleFailable2 41 | from returns.primitives.hkt import SupportsKind2 42 | 43 | _FirstType = TypeVar('_FirstType') 44 | _SecondType = TypeVar('_SecondType') 45 | 46 | @final 47 | class MyClass( 48 | SupportsKind2['MyClass', _FirstType, _SecondType], 49 | SingleFailable2[_FirstType, _SecondType], 50 | ): 51 | ... 52 | out: | 53 | main:9: error: Final class main.MyClass has abstract attributes "apply", "bind", "empty", "from_value", "lash", "map" [misc] 54 | -------------------------------------------------------------------------------- /typesafety/test_interfaces/test_specific/test_io/test_io_based.yml: -------------------------------------------------------------------------------- 1 | - case: io_based_inheritance_missing 2 | disable_cache: false 3 | main: | 4 | from typing import TypeVar, final 5 | from returns.interfaces.specific.io import IOBased1 6 | from returns.primitives.hkt import SupportsKind1 7 | 8 | _ValueType = TypeVar('_ValueType') 9 | 10 | @final 11 | class MyClass( 12 | SupportsKind1['MyClass', _ValueType], 13 | IOBased1[_ValueType], 14 | ): 15 | ... 16 | out: | 17 | main:8: error: Final class main.MyClass has abstract attributes "apply", "bind", "bind_io", "equals", "from_io", "from_value", "map" [misc] 18 | -------------------------------------------------------------------------------- /typesafety/test_interfaces/test_swappable/test_inheritance.yml: -------------------------------------------------------------------------------- 1 | - case: swappable_inheritance_correct2 2 | disable_cache: false 3 | main: | 4 | from typing import TypeVar 5 | from returns.interfaces.swappable import Swappable2 6 | from returns.primitives.hkt import SupportsKind2 7 | 8 | _FirstType = TypeVar('_FirstType') 9 | _SecondType = TypeVar('_SecondType') 10 | 11 | class MyClass( 12 | SupportsKind2['MyClass', _FirstType, _SecondType], 13 | Swappable2[_FirstType, _SecondType], 14 | ): 15 | def swap(self) -> MyClass[_SecondType, _FirstType]: 16 | ... 17 | 18 | 19 | - case: swappable_inheritance_missing 20 | disable_cache: false 21 | main: | 22 | from typing import TypeVar, final 23 | from returns.interfaces.swappable import Swappable2 24 | from returns.primitives.hkt import SupportsKind2 25 | 26 | _FirstType = TypeVar('_FirstType') 27 | _SecondType = TypeVar('_SecondType') 28 | 29 | @final 30 | class MyClass( 31 | SupportsKind2['MyClass', _FirstType, _SecondType], 32 | Swappable2[_FirstType, _SecondType], 33 | ): 34 | ... 35 | out: | 36 | main:9: error: Final class main.MyClass has abstract attributes "alt", "map", "swap" [misc] 37 | 38 | 39 | - case: swappable_inheritance_incorrect2 40 | disable_cache: false 41 | main: | 42 | from typing import TypeVar 43 | from returns.interfaces.swappable import Swappable2 44 | from returns.primitives.hkt import SupportsKind2 45 | 46 | _FirstType = TypeVar('_FirstType') 47 | _SecondType = TypeVar('_SecondType') 48 | _UpdatedType = TypeVar('_UpdatedType') 49 | 50 | class MyClass( 51 | SupportsKind2['MyClass', _FirstType, _SecondType], 52 | Swappable2[_FirstType, _SecondType], 53 | ): 54 | def swap(self) -> MyClass[_FirstType, _SecondType]: 55 | ... 56 | out: | 57 | main:13: error: Return type "MyClass[_FirstType, _SecondType]" of "swap" incompatible with return type "KindN[MyClass[_FirstType, _SecondType], _SecondType, _FirstType, Never]" in supertype "SwappableN" [override] 58 | -------------------------------------------------------------------------------- /typesafety/test_io/test_io_container/test_do.yml: -------------------------------------------------------------------------------- 1 | - case: do_types_missmatch 2 | disable_cache: false 3 | main: | 4 | from returns.io import IO 5 | from returns.result import Success 6 | 7 | IO.do( 8 | x + y 9 | for x in Success(1) # E: Invalid type supplied in do-notation: expected "returns.io.IO[Any]", got "returns.result.Success[builtins.int]" [misc] 10 | for y in IO(2.5) 11 | ) 12 | 13 | 14 | - case: do_with_if 15 | disable_cache: false 16 | main: | 17 | from returns.io import IO 18 | 19 | IO.do( # E: Using "if" conditions inside a generator is not allowed [misc] 20 | x + y 21 | for x in IO(1) 22 | for y in IO(2.5) 23 | if y > 5 24 | ) 25 | 26 | 27 | - case: do_with_var 28 | disable_cache: false 29 | main: | 30 | from returns.io import IO 31 | 32 | x = ( 33 | x + y 34 | for x in IO(1) 35 | for y in IO(2.5) 36 | ) 37 | 38 | IO.do(x) # E: Literal generator expression is required, not a variable or function call [misc] 39 | -------------------------------------------------------------------------------- /typesafety/test_io/test_io_container/test_io_base.yml: -------------------------------------------------------------------------------- 1 | - case: io_constructor1 2 | disable_cache: false 3 | main: | 4 | from returns.io import IO 5 | 6 | reveal_type(IO(1)) # N: Revealed type is "returns.io.IO[builtins.int]" 7 | 8 | 9 | - case: io_constructor2 10 | disable_cache: false 11 | main: | 12 | from returns.io import IO 13 | 14 | reveal_type(IO.from_value(1)) # N: Revealed type is "returns.io.IO[builtins.int]" 15 | 16 | 17 | - case: io_constructor3 18 | disable_cache: false 19 | main: | 20 | from returns.io import IO 21 | 22 | reveal_type(IO.from_io(IO(1))) # N: Revealed type is "returns.io.IO[builtins.int]" 23 | 24 | 25 | - case: io_bind 26 | disable_cache: false 27 | main: | 28 | from returns.io import IO 29 | 30 | def bind_io(input_io: int) -> IO[str]: 31 | ... 32 | 33 | reveal_type(IO(1).bind(bind_io)) # N: Revealed type is "returns.io.IO[builtins.str]" 34 | 35 | 36 | 37 | - case: io_bind_io 38 | disable_cache: false 39 | main: | 40 | from returns.io import IO 41 | 42 | def bind_io(input_io: int) -> IO[str]: 43 | ... 44 | 45 | reveal_type(IO(1).bind_io(bind_io)) # N: Revealed type is "returns.io.IO[builtins.str]" 46 | 47 | 48 | - case: io_map 49 | disable_cache: false 50 | main: | 51 | from returns.io import IO 52 | 53 | reveal_type(IO(1).map(str)) # N: Revealed type is "returns.io.IO[builtins.str]" 54 | 55 | 56 | - case: io_apply 57 | disable_cache: false 58 | main: | 59 | from returns.io import IO 60 | 61 | def transform(arg: int) -> str: 62 | ... 63 | 64 | reveal_type(IO(1).apply(IO(transform))) # N: Revealed type is "returns.io.IO[builtins.str]" 65 | -------------------------------------------------------------------------------- /typesafety/test_io/test_io_container/test_io_type_cast.yml: -------------------------------------------------------------------------------- 1 | - case: io_correct_cast 2 | disable_cache: false 3 | main: | 4 | from returns.io import IO 5 | 6 | first: IO[ValueError] 7 | second: IO[Exception] = first 8 | reveal_type(second) # N: Revealed type is "returns.io.IO[builtins.Exception]" 9 | 10 | 11 | - case: io_from_ioresult 12 | disable_cache: false 13 | main: | 14 | from returns.io import IO, IOResult 15 | 16 | x: IOResult[int, str] 17 | 18 | reveal_type(IO.from_ioresult(x)) # N: Revealed type is "returns.io.IO[returns.result.Result[builtins.int, builtins.str]]" 19 | 20 | 21 | - case: io_getattr 22 | disable_cache: false 23 | main: | 24 | from returns.io import IO 25 | 26 | x: IO[int] 27 | x.missing # E: "IO[int]" has no attribute "missing" [attr-defined] 28 | -------------------------------------------------------------------------------- /typesafety/test_io/test_ioresult_container/test_construct_iofailure.yml: -------------------------------------------------------------------------------- 1 | - case: iofailure_lash 2 | disable_cache: false 3 | main: | 4 | from returns.io import IOFailure, IOResult 5 | 6 | def returns_result(param: int) -> IOResult[str, Exception]: 7 | ... 8 | 9 | first: IOResult[str, int] = IOFailure(1) 10 | reveal_type(first.lash(returns_result)) # N: Revealed type is "returns.io.IOResult[builtins.str, builtins.Exception]" 11 | 12 | 13 | - case: iofailure_alt 14 | disable_cache: false 15 | main: | 16 | from returns.io import IOFailure 17 | 18 | reveal_type(IOFailure(1).alt(str)) # N: Revealed type is "returns.io.IOResult[Any, builtins.str]" 19 | 20 | 21 | - case: iofailure_iofailure 22 | disable_cache: false 23 | main: | 24 | from returns.io import IOFailure 25 | 26 | reveal_type(IOFailure(1).failure()) # N: Revealed type is "returns.io.IO[builtins.int]" 27 | -------------------------------------------------------------------------------- /typesafety/test_io/test_ioresult_container/test_impure_safe.yml: -------------------------------------------------------------------------------- 1 | - case: impure_decorator_no_params 2 | disable_cache: false 3 | main: | 4 | from returns.io import impure_safe 5 | 6 | @impure_safe 7 | def test(arg: str) -> int: 8 | return 1 9 | 10 | reveal_type(test) # N: Revealed type is "def (arg: builtins.str) -> returns.io.IOResult[builtins.int, builtins.Exception]" 11 | 12 | 13 | - case: impure_decorator_passing_exceptions_no_params 14 | disable_cache: false 15 | main: | 16 | from returns.io import impure_safe 17 | 18 | @impure_safe((ValueError,)) 19 | def test1(arg: str) -> int: 20 | return 1 21 | 22 | reveal_type(test1) # N: Revealed type is "def (arg: builtins.str) -> returns.io.IOResult[builtins.int, builtins.ValueError]" 23 | 24 | @impure_safe(exceptions=(ValueError,)) 25 | def test2(arg: str) -> int: 26 | return 1 27 | 28 | reveal_type(test2) # N: Revealed type is "def (arg: builtins.str) -> returns.io.IOResult[builtins.int, builtins.ValueError]" 29 | -------------------------------------------------------------------------------- /typesafety/test_io/test_ioresult_container/test_ioresult_helpers.yml: -------------------------------------------------------------------------------- 1 | - case: ioresult_from_typecast 2 | disable_cache: false 3 | main: | 4 | from returns.io import IO, IOResult 5 | from returns.result import Result 6 | 7 | container: IO[Result[int, str]] 8 | 9 | reveal_type(IOResult.from_typecast(container)) # N: Revealed type is "returns.io.IOResult[builtins.int, builtins.str]" 10 | 11 | 12 | - case: ioresult_from_io 13 | disable_cache: false 14 | main: | 15 | from returns.io import IO, IOResult 16 | 17 | container: IO[str] 18 | 19 | reveal_type(IOResult.from_io(container)) # N: Revealed type is "returns.io.IOResult[builtins.str, Any]" 20 | 21 | 22 | - case: ioresult_from_failed_io 23 | disable_cache: false 24 | main: | 25 | from returns.io import IO, IOResult 26 | 27 | container: IO[str] 28 | 29 | reveal_type(IOResult.from_failed_io(container)) # N: Revealed type is "returns.io.IOResult[Any, builtins.str]" 30 | -------------------------------------------------------------------------------- /typesafety/test_maybe/test_do.yml: -------------------------------------------------------------------------------- 1 | - case: do_all_errors 2 | disable_cache: false 3 | main: | 4 | from returns.maybe import Maybe 5 | 6 | reveal_type(Maybe.do( # N: Revealed type is "returns.maybe.Maybe[Any]" 7 | first / second 8 | for first in Maybe.empty 9 | for second in Maybe.empty 10 | )) 11 | 12 | 13 | - case: do_types_missmatch 14 | disable_cache: false 15 | main: | 16 | from returns.maybe import Maybe 17 | from returns.result import Success 18 | 19 | Maybe.do( 20 | x + y 21 | for x in Success(1) # E: Invalid type supplied in do-notation: expected "returns.maybe.Maybe[Any]", got "returns.result.Success[builtins.int]" [misc] 22 | for y in Maybe.from_value(2.5) 23 | ) 24 | 25 | 26 | - case: do_types_converted 27 | disable_cache: false 28 | main: | 29 | from returns.maybe import Maybe 30 | from returns.result import Result 31 | from returns.converters import result_to_maybe 32 | 33 | a: Result[int, str] 34 | 35 | reveal_type(Maybe.do( # N: Revealed type is "returns.maybe.Maybe[builtins.float]" 36 | x + y 37 | for x in result_to_maybe(a) 38 | for y in Maybe.from_value(2.5) 39 | )) 40 | 41 | 42 | - case: do_with_if 43 | disable_cache: false 44 | main: | 45 | from returns.maybe import Maybe 46 | 47 | Maybe.do( # E: Using "if" conditions inside a generator is not allowed [misc] 48 | x + y 49 | for x in Maybe.from_value(1) 50 | for y in Maybe.from_value(2.5) 51 | if y > 5 52 | ) 53 | 54 | 55 | - case: do_with_var 56 | disable_cache: false 57 | main: | 58 | from returns.maybe import Maybe 59 | 60 | x = ( 61 | x + y 62 | for x in Maybe.from_value(1) 63 | for y in Maybe.from_value(2.5) 64 | ) 65 | 66 | Maybe.do(x) # E: Literal generator expression is required, not a variable or function call [misc] 67 | -------------------------------------------------------------------------------- /typesafety/test_maybe/test_maybe_type_cast.yml: -------------------------------------------------------------------------------- 1 | - case: maybe_correct_cast 2 | disable_cache: false 3 | main: | 4 | from returns.maybe import Maybe 5 | 6 | first: Maybe[ValueError] 7 | second: Maybe[Exception] = first 8 | reveal_type(second) # N: Revealed type is "returns.maybe.Maybe[builtins.Exception]" 9 | 10 | 11 | - case: maybe_getattr 12 | disable_cache: false 13 | main: | 14 | from returns.maybe import Maybe 15 | 16 | x: Maybe[int] 17 | x.missing # E: "Maybe[int]" has no attribute "missing" [attr-defined] 18 | 19 | 20 | - case: maybe_some_constructor 21 | disable_cache: false 22 | main: | 23 | from returns.maybe import Some 24 | 25 | reveal_type(Some(1)) # N: Revealed type is "returns.maybe.Some[builtins.int]" 26 | 27 | 28 | - case: maybe_nothing_const 29 | disable_cache: false 30 | main: | 31 | from returns.maybe import Nothing 32 | 33 | reveal_type(Nothing) # N: Revealed type is "returns.maybe.Maybe[Never]" 34 | -------------------------------------------------------------------------------- /typesafety/test_methods/test_partition.yml: -------------------------------------------------------------------------------- 1 | - case: partition_result 2 | disable_cache: false 3 | main: | 4 | from typing import List 5 | from returns.result import Success, Failure, Result 6 | from returns.methods import partition 7 | 8 | x: List[Result[int, str]] 9 | reveal_type(partition(x)) # N: Revealed type is "Tuple[builtins.list[builtins.int], builtins.list[builtins.str]]" 10 | 11 | - case: partition_io_results 12 | disable_cache: false 13 | main: | 14 | from typing import Tuple 15 | from returns.result import Success, Failure 16 | from returns.methods import partition 17 | from returns.io import IO, IOResult, IOSuccess 18 | 19 | x: Tuple[IOResult[int, str], IOResult[int, str]] 20 | reveal_type(partition(x)) # N: Revealed type is "Tuple[builtins.list[returns.io.IO[builtins.int]], builtins.list[returns.io.IO[builtins.str]]]" 21 | 22 | - case: partition_maybe 23 | disable_cache: false 24 | main: | 25 | from typing import List, Tuple 26 | from returns.maybe import Maybe 27 | from returns.methods import partition 28 | 29 | x: List[Maybe[int]] 30 | 31 | reveal_type(partition(x)) # N: Revealed type is "Tuple[builtins.list[builtins.int], builtins.list[None]]" 32 | -------------------------------------------------------------------------------- /typesafety/test_methods/test_unwrap_or_failure.yml: -------------------------------------------------------------------------------- 1 | - case: unwrap_or_failure_result 2 | disable_cache: false 3 | main: | 4 | from returns.methods import unwrap_or_failure 5 | from returns.result import Result 6 | 7 | x: Result[int, str] 8 | reveal_type(unwrap_or_failure(x)) # N: Revealed type is "Union[builtins.int, builtins.str]" 9 | 10 | 11 | - case: unwrap_or_failure_ioresult 12 | disable_cache: false 13 | main: | 14 | from returns.methods import unwrap_or_failure 15 | from returns.io import IOResult 16 | 17 | x: IOResult[int, str] 18 | reveal_type(unwrap_or_failure(x)) # N: Revealed type is "Union[returns.io.IO[builtins.int], returns.io.IO[builtins.str]]" 19 | 20 | 21 | - case: unwrap_or_failure_custom_type 22 | disable_cache: false 23 | main: | 24 | from typing import TypeVar 25 | from returns.interfaces.unwrappable import Unwrappable 26 | from returns.methods import unwrap_or_failure 27 | 28 | ValueType = TypeVar('ValueType') 29 | ErrorType = TypeVar('ErrorType') 30 | 31 | class MyOwn(Unwrappable[ValueType, ErrorType]): 32 | ... 33 | 34 | x: MyOwn[int, str] 35 | reveal_type(unwrap_or_failure(x)) # N: Revealed type is "Union[builtins.int, builtins.str]" 36 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_flow/test_flow_args.yml: -------------------------------------------------------------------------------- 1 | - case: flow_zero_args 2 | disable_cache: false 3 | main: | 4 | from returns.pipeline import flow 5 | 6 | reveal_type(flow()) 7 | out: | 8 | main:3: error: Missing positional argument "instance" in call to "flow" [call-arg] 9 | main:3: note: Revealed type is "Never" 10 | 11 | 12 | - case: flow_one_arg 13 | disable_cache: false 14 | main: | 15 | from returns.pipeline import flow 16 | 17 | reveal_type(flow(1)) 18 | out: | 19 | main:3: error: Too few arguments for "flow" [misc] 20 | main:3: note: Revealed type is "Never" 21 | 22 | 23 | - case: flow_star_args 24 | disable_cache: false 25 | main: | 26 | from returns.pipeline import flow 27 | from returns.functions import identity 28 | 29 | reveal_type( 30 | flow( # N: Revealed type is "builtins.int" 31 | 1, 32 | identity, 33 | identity, 34 | identity, 35 | identity, 36 | identity, 37 | identity, 38 | identity, 39 | identity, 40 | identity, 41 | identity, 42 | identity, 43 | identity, 44 | identity, 45 | identity, 46 | identity, 47 | identity, 48 | identity, 49 | identity, 50 | identity, 51 | ) 52 | ) 53 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_flow/test_flow_curry.yml: -------------------------------------------------------------------------------- 1 | - case: flow_function_with_curried1 2 | disable_cache: false 3 | main: | 4 | from returns.pipeline import flow 5 | from returns.curry import curry 6 | from returns.functions import identity 7 | 8 | @curry 9 | def curried(a: int, b: int) -> float: 10 | ... 11 | 12 | reveal_type(flow(1, curried)(1)) # N: Revealed type is "builtins.float" 13 | 14 | 15 | - case: flow_function_with_curried2 16 | disable_cache: false 17 | main: | 18 | from returns.pipeline import flow 19 | from returns.curry import curry 20 | from returns.functions import identity 21 | 22 | @curry 23 | def curried(a: int, b: int) -> float: 24 | ... 25 | 26 | reveal_type(flow(1, curried, identity)(1)) # N: Revealed type is "builtins.float" 27 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_flow/test_flow_errors.yml: -------------------------------------------------------------------------------- 1 | - case: flow_function_error 2 | disable_cache: false 3 | main: | 4 | from returns.pipeline import flow 5 | 6 | def convert(arg: str) -> float: 7 | ... 8 | 9 | reveal_type(flow('1', int, convert)) 10 | out: | 11 | main:6: error: Argument 1 to "convert" has incompatible type "int"; expected "str" [arg-type] 12 | main:6: note: Revealed type is "builtins.float" 13 | 14 | 15 | - case: flow_wrong_steps_error 16 | disable_cache: false 17 | main: | 18 | from returns.pipeline import flow 19 | 20 | reveal_type(flow('a', [], int)) 21 | out: | 22 | main:3: error: "List[Never]" not callable [operator] 23 | main:3: note: Revealed type is "builtins.int" 24 | 25 | 26 | - case: flow_function_first_arg_error 27 | disable_cache: false 28 | main: | 29 | from returns.pipeline import flow 30 | 31 | def convert(arg: str) -> float: 32 | ... 33 | 34 | reveal_type(flow(1, convert)) 35 | out: | 36 | main:6: error: Argument 1 to "convert" has incompatible type "int"; expected "str" [arg-type] 37 | main:6: note: Revealed type is "builtins.float" 38 | 39 | 40 | - case: flow_function_without_args_error 41 | disable_cache: false 42 | main: | 43 | from returns.pipeline import flow 44 | 45 | def convert() -> float: 46 | ... 47 | 48 | reveal_type(flow(1, convert)) 49 | out: | 50 | main:6: error: Too many arguments for "convert" [call-arg] 51 | main:6: note: Revealed type is "builtins.float" 52 | 53 | 54 | - case: flow_function_with_too_many_args_error 55 | disable_cache: false 56 | main: | 57 | from returns.pipeline import flow 58 | 59 | def convert(first: str, other: int) -> float: 60 | ... 61 | 62 | reveal_type(flow(1, convert)) 63 | out: | 64 | main:6: error: Missing positional argument "other" in call to "convert" [call-arg] 65 | main:6: error: Argument 1 to "convert" has incompatible type "int"; expected "str" [arg-type] 66 | main:6: note: Revealed type is "builtins.float" 67 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_flow/test_flow_generics.yml: -------------------------------------------------------------------------------- 1 | - case: flow_generic_function 2 | disable_cache: false 3 | main: | 4 | from returns.pipeline import flow 5 | from returns.functions import identity 6 | from typing import TypeVar 7 | 8 | _NewValueType = TypeVar('_NewValueType') 9 | 10 | def test(arg: _NewValueType) -> _NewValueType: 11 | x = flow(arg, identity) 12 | reveal_type(x) # N: Revealed type is "_NewValueType`-1" 13 | return x 14 | 15 | 16 | - case: flow_generic_argument 17 | disable_cache: false 18 | main: | 19 | from returns.pipeline import flow 20 | from returns.functions import identity 21 | from typing import TypeVar 22 | 23 | _NewValueType = TypeVar('_NewValueType') 24 | 25 | def test(arg: _NewValueType) -> _NewValueType: 26 | x = flow(arg, str) 27 | reveal_type(x) # N: Revealed type is "builtins.str" 28 | return arg 29 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_is_successful.yml: -------------------------------------------------------------------------------- 1 | - case: result_is_successful 2 | disable_cache: false 3 | main: | 4 | from returns.pipeline import is_successful 5 | from returns.result import Result 6 | 7 | def returns_result() -> Result[int, str]: 8 | ... 9 | 10 | reveal_type(is_successful(returns_result())) # N: Revealed type is "builtins.bool" 11 | 12 | 13 | - case: ioresult_is_successful 14 | disable_cache: false 15 | main: | 16 | from returns.pipeline import is_successful 17 | from returns.io import IOResult 18 | 19 | def returns_ioresult() -> IOResult[int, str]: 20 | ... 21 | 22 | reveal_type(is_successful(returns_ioresult())) # N: Revealed type is "builtins.bool" 23 | 24 | 25 | - case: maybe_is_successful 26 | disable_cache: false 27 | main: | 28 | from returns.pipeline import is_successful 29 | from returns.maybe import Maybe 30 | 31 | reveal_type(is_successful(Maybe.from_value(1))) # N: Revealed type is "builtins.bool" 32 | 33 | 34 | - case: custom_type_is_successful 35 | disable_cache: false 36 | main: | 37 | from returns.pipeline import is_successful 38 | from returns.primitives.hkt import Kind2 39 | from returns.primitives.exceptions import UnwrapFailedError 40 | from returns.interfaces.unwrappable import Unwrappable 41 | from typing import TypeVar 42 | 43 | T = TypeVar('T') 44 | N = TypeVar('N') 45 | 46 | class MyOwn( 47 | Kind2['MyOwn', T, N], 48 | Unwrappable[T, N], 49 | ): 50 | def __init__(self, value: T, error: N) -> None: 51 | self.value = value 52 | self.error = error 53 | 54 | def unwrap(self) -> T: 55 | if self.error: 56 | raise UnwrapFailedError(self) 57 | return self.value 58 | 59 | def failure(self) -> N: 60 | if self.value: 61 | raise UnwrapFailedError(self) 62 | return self.error 63 | 64 | x: MyOwn[int, str] 65 | reveal_type(x.unwrap()) # N: Revealed type is "builtins.int" 66 | reveal_type(x.failure()) # N: Revealed type is "builtins.str" 67 | reveal_type(is_successful(x)) # N: Revealed type is "builtins.bool" 68 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_managed/test_managed_errors.yml: -------------------------------------------------------------------------------- 1 | - case: managed_with_non_none_release 2 | disable_cache: false 3 | main: | 4 | from returns.io import IOResult 5 | from returns.pipeline import managed 6 | from returns.result import Result 7 | 8 | def use(acquired_value: int) -> IOResult[float, str]: 9 | ... 10 | 11 | def release( 12 | acquired_value: int, 13 | use_value: Result[float, str], 14 | ) -> IOResult[float, str]: 15 | ... 16 | 17 | x: IOResult[int, str] 18 | managed(use, release)(x) # E: Argument 2 to "managed" has incompatible type "Callable[[int, Result[float, str]], IOResult[float, str]]"; expected "Callable[[int, Result[float, str]], KindN[IOResult[Any, Any], None, str, Never]]" [arg-type] 19 | 20 | 21 | - case: managed_with_non_matching_use_release_types 22 | disable_cache: false 23 | main: | 24 | from returns.io import IOResult 25 | from returns.pipeline import managed 26 | from returns.result import Result 27 | 28 | def use(acquired_value: int) -> IOResult[float, str]: 29 | ... 30 | 31 | def release( 32 | acquired_value: int, 33 | use_value: Result[str, str], 34 | ) -> IOResult[None, str]: 35 | ... 36 | 37 | x: IOResult[int, str] 38 | managed(use, release)(x) # E: Cannot infer type argument 3 of "managed" [misc] 39 | 40 | 41 | - case: managed_with_wrong_container_input 42 | disable_cache: false 43 | main: | 44 | from returns.io import IOResult 45 | from returns.pipeline import managed 46 | from returns.result import Result 47 | 48 | def use(acquired_value: int) -> IOResult[float, str]: 49 | ... 50 | 51 | def release( 52 | acquired_value: int, 53 | use_value: Result[float, str], 54 | ) -> IOResult[None, str]: 55 | ... 56 | 57 | x: IOResult[str, str] 58 | managed(use, release)(x) # E: Argument 1 has incompatible type "IOResult[str, str]"; expected "KindN[IOResult[Any, Any], int, str, Never]" [arg-type] 59 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_pipe/test_pipe_callable_protocol.yml: -------------------------------------------------------------------------------- 1 | - case: pipe_regular_callable 2 | disable_cache: false 3 | main: | 4 | from typing import Callable 5 | from returns.pipeline import pipe 6 | 7 | def convert(arg: str) -> float: 8 | ... 9 | 10 | def callback(f: Callable[[str], bool]) -> bool: 11 | return f('a') 12 | 13 | predefined = pipe(convert, int, bool) 14 | reveal_type(callback(predefined)) # N: Revealed type is "builtins.bool" 15 | 16 | 17 | - case: pipe_generic_callable1 18 | disable_cache: false 19 | main: | 20 | from typing import Callable, TypeVar 21 | from returns.pipeline import pipe 22 | 23 | T = TypeVar('T') 24 | R = TypeVar('R') 25 | 26 | def callback(f: Callable[[T], R], i: T) -> R: 27 | return f(i) 28 | 29 | def first(a: int) -> float: 30 | ... 31 | 32 | def second(a: float) -> str: 33 | ... 34 | 35 | predefined = pipe(first, second) 36 | reveal_type(callback(predefined, 1)) # N: Revealed type is "builtins.str" 37 | 38 | 39 | - case: pipe_generic_callable2 40 | disable_cache: false 41 | main: | 42 | from typing import Callable, TypeVar 43 | from returns.pipeline import pipe 44 | 45 | T = TypeVar('T') 46 | R = TypeVar('R') 47 | 48 | def callback(f: Callable[[T], R]) -> R: 49 | ... 50 | 51 | def first(a: int) -> float: 52 | ... 53 | 54 | def second(a: float) -> str: 55 | ... 56 | 57 | predefined = pipe(first, second) 58 | reveal_type(callback(predefined)) # N: Revealed type is "builtins.str" 59 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_pipe/test_pipe_curry.yml: -------------------------------------------------------------------------------- 1 | - case: pipe_function_with_curried 2 | disable_cache: false 3 | main: | 4 | from returns.pipeline import pipe 5 | from returns.curry import curry 6 | from returns.functions import identity 7 | 8 | @curry 9 | def curried(a: int, b: int) -> float: 10 | ... 11 | 12 | reveal_type(pipe(curried, identity)(1)(2)) # N: Revealed type is "builtins.float" 13 | -------------------------------------------------------------------------------- /typesafety/test_pipeline/test_pipe/test_pipe_generic.yml: -------------------------------------------------------------------------------- 1 | - case: pipe_generic_function 2 | disable_cache: false 3 | main: | 4 | from returns.pipeline import pipe 5 | from returns.functions import identity 6 | from typing import TypeVar 7 | 8 | _NewValueType = TypeVar('_NewValueType') 9 | 10 | def test(arg: _NewValueType) -> _NewValueType: 11 | x = pipe(identity)(arg) 12 | reveal_type(x) # N: Revealed type is "_NewValueType`-1" 13 | return x 14 | 15 | 16 | - case: pipe_generic_argument 17 | disable_cache: false 18 | main: | 19 | from returns.pipeline import pipe 20 | from returns.functions import identity 21 | from typing import TypeVar 22 | 23 | _NewValueType = TypeVar('_NewValueType') 24 | 25 | def test(arg: _NewValueType) -> _NewValueType: 26 | x = pipe(identity, str)(arg) 27 | reveal_type(x) # N: Revealed type is "builtins.str" 28 | return arg 29 | -------------------------------------------------------------------------------- /typesafety/test_pointfree/test_bind_async_context_future_result.yml: -------------------------------------------------------------------------------- 1 | - case: bind_async_context_future_result_wrong 2 | disable_cache: false 3 | main: | 4 | from returns.pointfree import bind_async_context_future_result 5 | from returns.context import RequiresContextFutureResult 6 | 7 | async def test(arg: float) -> RequiresContextFutureResult[int, str, str]: 8 | ... 9 | 10 | x: RequiresContextFutureResult[float, bool, bool] 11 | bind_async_context_future_result(test)(x) # E: Argument 1 has incompatible type "RequiresContextFutureResult[float, bool, bool]"; expected "KindN[RequiresContextFutureResult[Any, Any, Any], float, str, str]" [arg-type] 12 | 13 | 14 | - case: bind_async_context_future_result_requires_context_future_result 15 | disable_cache: false 16 | main: | 17 | from returns.pointfree import bind_async_context_future_result 18 | from returns.context import RequiresContextFutureResult 19 | 20 | async def test(arg: float) -> RequiresContextFutureResult[int, str, bool]: 21 | ... 22 | 23 | x: RequiresContextFutureResult[float, str, bool] 24 | reveal_type(bind_async_context_future_result(test)(x)) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.int, builtins.str, builtins.bool]" 25 | -------------------------------------------------------------------------------- /typesafety/test_pointfree/test_bind_context_future_result.yml: -------------------------------------------------------------------------------- 1 | - case: bind_context_future_result_wrong 2 | disable_cache: false 3 | main: | 4 | from returns.pointfree import bind_context_future_result 5 | from returns.context import RequiresContextFutureResult 6 | 7 | def test(arg: float) -> RequiresContextFutureResult[int, str, str]: 8 | ... 9 | 10 | x: RequiresContextFutureResult[float, bool, bool] 11 | bind_context_future_result(test)(x) # E: Argument 1 has incompatible type "RequiresContextFutureResult[float, bool, bool]"; expected "KindN[RequiresContextFutureResult[Any, Any, Any], float, str, str]" [arg-type] 12 | 13 | 14 | - case: bind_context_future_result_requires_context_future_result 15 | disable_cache: false 16 | main: | 17 | from returns.pointfree import bind_context_future_result 18 | from returns.context import RequiresContextFutureResult 19 | 20 | def test(arg: float) -> RequiresContextFutureResult[int, str, bool]: 21 | ... 22 | 23 | x: RequiresContextFutureResult[float, str, bool] 24 | reveal_type(bind_context_future_result(test)(x)) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.int, builtins.str, builtins.bool]" 25 | -------------------------------------------------------------------------------- /typesafety/test_pointfree/test_bind_context_ioresult.yml: -------------------------------------------------------------------------------- 1 | - case: bind_context_ioresult_wrong 2 | disable_cache: false 3 | main: | 4 | from returns.pointfree import bind_context_ioresult 5 | from returns.context import RequiresContextIOResult 6 | 7 | def test(arg: float) -> RequiresContextIOResult[int, str, str]: 8 | ... 9 | 10 | x: RequiresContextIOResult[float, bool, bool] 11 | bind_context_ioresult(test)(x) # E: Argument 1 has incompatible type "RequiresContextIOResult[float, bool, bool]"; expected "KindN[RequiresContextIOResult[Any, Any, Any], float, str, str]" [arg-type] 12 | 13 | 14 | - case: bind_context_ioresult_requires_context_ioresult 15 | disable_cache: false 16 | main: | 17 | from returns.pointfree import bind_context_ioresult 18 | from returns.context import RequiresContextIOResult 19 | 20 | def test(arg: float) -> RequiresContextIOResult[int, str, bool]: 21 | ... 22 | 23 | x: RequiresContextIOResult[float, str, bool] 24 | reveal_type(bind_context_ioresult(test)(x)) # N: Revealed type is "returns.context.requires_context_ioresult.RequiresContextIOResult[builtins.int, builtins.str, builtins.bool]" 25 | 26 | 27 | - case: bind_context_ioresult_requires_context_future_result 28 | disable_cache: false 29 | main: | 30 | from returns.pointfree import bind_context_ioresult 31 | from returns.context import RequiresContextIOResult, RequiresContextFutureResult 32 | 33 | def test(arg: float) -> RequiresContextIOResult[int, str, bool]: 34 | ... 35 | 36 | x: RequiresContextFutureResult[float, str, bool] 37 | reveal_type(bind_context_ioresult(test)(x)) # N: Revealed type is "returns.context.requires_context_future_result.RequiresContextFutureResult[builtins.int, builtins.str, builtins.bool]" 38 | -------------------------------------------------------------------------------- /typesafety/test_pointfree/test_bind_optional.yml: -------------------------------------------------------------------------------- 1 | - case: bind_optional_wrong_instance_type 2 | disable_cache: false 3 | main: | 4 | from returns.pointfree import bind_optional 5 | from returns.maybe import Maybe 6 | from typing import Optional 7 | 8 | def test(arg: float) -> Optional[int]: 9 | ... 10 | 11 | x: Maybe[str] 12 | bind_optional(test)(x) 13 | out: | 14 | main:9: error: Argument 1 has incompatible type "Maybe[str]"; expected "KindN[Maybe[Any], float, Never, Never]" [arg-type] 15 | 16 | 17 | - case: bind_optional_maybe 18 | disable_cache: false 19 | main: | 20 | from returns.pointfree import bind_optional 21 | from returns.maybe import Maybe 22 | from typing import Optional 23 | 24 | def test(arg: float) -> Optional[str]: 25 | ... 26 | 27 | x: Maybe[float] 28 | reveal_type(bind_optional(test)(x)) # N: Revealed type is "returns.maybe.Maybe[builtins.str]" 29 | -------------------------------------------------------------------------------- /typesafety/test_primitives/test_hkt/test_kinded/test_kinded_overload.yml: -------------------------------------------------------------------------------- 1 | - case: kinded_with_any 2 | disable_cache: false 3 | main: | 4 | from typing import TypeVar, overload, Optional 5 | from returns.maybe import Maybe 6 | from returns.interfaces.mappable import MappableN 7 | from returns.primitives.hkt import Kind1, kinded 8 | 9 | _ValueType = TypeVar('_ValueType') 10 | _NewType = TypeVar('_NewType') 11 | _MappableKind = TypeVar('_MappableKind', bound=MappableN) 12 | 13 | @overload 14 | def _test( 15 | instance: Kind1[_MappableKind, _ValueType], 16 | ) -> Kind1[_MappableKind, None]: 17 | ... 18 | 19 | @overload 20 | def _test( 21 | instance: Kind1[_MappableKind, _ValueType], 22 | value: _NewType, 23 | ) -> Kind1[_MappableKind, _NewType]: 24 | ... 25 | 26 | def _test( 27 | instance: Kind1[_MappableKind, _ValueType], 28 | value: Optional[_NewType] = None, 29 | ) -> Kind1[_MappableKind, Optional[_NewType]]: 30 | ... 31 | 32 | test = kinded(_test) 33 | x: Maybe[int] 34 | reveal_type(test(x)) # N: Revealed type is "returns.maybe.Maybe[None]" 35 | reveal_type(test(x, 'a')) # N: Revealed type is "returns.maybe.Maybe[builtins.str]" 36 | -------------------------------------------------------------------------------- /typesafety/test_primitives/test_hkt/test_kindn/test_kindn.yml: -------------------------------------------------------------------------------- 1 | - case: kind_params 2 | disable_cache: false 3 | parametrized: 4 | - count: 1 5 | expected: 2 6 | - count: 2 7 | expected: 3 8 | - count: 3 9 | expected: 4 10 | main: | 11 | from returns.primitives.hkt import Kind{{ count }} 12 | 13 | container: Kind{{ count }}[object, int, str, bool, float] 14 | out: | 15 | main:3: error: Bad number of arguments for type alias, expected {{ expected }}, given 5 [type-arg] 16 | -------------------------------------------------------------------------------- /typesafety/test_primitives/test_hkt/test_kindn/test_kindn_getattr.yml: -------------------------------------------------------------------------------- 1 | - case: kind_existing_getattr 2 | disable_cache: false 3 | main: | 4 | from returns.primitives.hkt import Kind1 5 | from typing import List 6 | 7 | container: Kind1[List, int] 8 | reveal_type(container.pop) # N: Revealed type is "def (typing.SupportsIndex =) -> builtins.int" 9 | 10 | 11 | - case: kind_missing_getattr 12 | disable_cache: false 13 | main: | 14 | from returns.primitives.hkt import Kind1 15 | from typing import List 16 | 17 | container: Kind1[List, int] 18 | container.missing # E: "List[Any]" has no attribute "missing" [attr-defined] 19 | 20 | 21 | - case: kind_any_getattr 22 | disable_cache: false 23 | main: | 24 | from returns.primitives.hkt import Kind1 25 | from typing import Any 26 | 27 | container: Kind1[Any, int] 28 | reveal_type(container.missing) # N: Revealed type is "Any" 29 | -------------------------------------------------------------------------------- /typesafety/test_primitives/test_hkt/test_supports_kind.yml: -------------------------------------------------------------------------------- 1 | - case: supports_kind_getattr_existing 2 | disable_cache: false 3 | main: | 4 | from returns.primitives.hkt import SupportsKind1 5 | from typing import List 6 | 7 | container: SupportsKind1[List, int] 8 | container.pop # E: "SupportsKindN[List[Any], int, Never, Never]" has no attribute "pop" [attr-defined] 9 | 10 | 11 | - case: supports_kind_getattr_missing 12 | disable_cache: false 13 | main: | 14 | from returns.primitives.hkt import SupportsKindN 15 | 16 | container: SupportsKindN[object, int, str, bool] 17 | container.missing 18 | out: | 19 | main:4: error: "SupportsKindN[object, int, str, bool]" has no attribute "missing" [attr-defined] 20 | 21 | 22 | - case: supports_kind_getattr_subclass 23 | disable_cache: false 24 | main: | 25 | from returns.primitives.hkt import SupportsKind1 26 | from typing import TypeVar 27 | 28 | T = TypeVar('T') 29 | 30 | class Custom(SupportsKind1['Custom', T]): 31 | existing: T 32 | 33 | container: Custom[int] 34 | reveal_type(container.existing) 35 | reveal_type(container.missing) 36 | out: | 37 | main:10: note: Revealed type is "builtins.int" 38 | main:11: error: "Custom[int]" has no attribute "missing" [attr-defined] 39 | main:11: note: Revealed type is "Any" 40 | -------------------------------------------------------------------------------- /typesafety/test_primitives/test_reawaitable/test_reawaitable_decorator.yml: -------------------------------------------------------------------------------- 1 | - case: reawaitable_decorator_with_args 2 | disable_cache: false 3 | main: | 4 | from typing import Optional 5 | from returns.primitives.reawaitable import reawaitable 6 | 7 | @reawaitable 8 | async def test(first: int, second: Optional[str] = None, *, kw: bool = True) -> int: 9 | ... 10 | 11 | reveal_type(test) # N: Revealed type is "def (first: builtins.int, second: Union[builtins.str, None] =, *, kw: builtins.bool =) -> typing.Coroutine[Any, Any, builtins.int]" 12 | -------------------------------------------------------------------------------- /typesafety/test_primitives/test_tracing/test_collect_traces.yml: -------------------------------------------------------------------------------- 1 | - case: collect_traces_context_manager_return_type_one 2 | skip: sys.version_info[:2] >= (3, 13) 3 | disable_cache: false 4 | main: | 5 | from returns.primitives.tracing import collect_traces 6 | 7 | reveal_type(collect_traces) # N: Revealed type is "Overload(def () -> contextlib.AbstractContextManager[None, Union[builtins.bool, None]], def [_FunctionType <: def (*Any, **Any) -> Any] (function: _FunctionType`-1) -> _FunctionType`-1)" 8 | 9 | - case: collect_traces_context_manager_return_type_two 10 | skip: sys.version_info[:2] >= (3, 13) 11 | disable_cache: false 12 | main: | 13 | from returns.primitives.tracing import collect_traces 14 | 15 | with reveal_type(collect_traces()): # N: Revealed type is "contextlib.AbstractContextManager[None, Union[builtins.bool, None]]" 16 | pass 17 | 18 | - case: collect_traces_decorated_function_return_type 19 | disable_cache: false 20 | main: | 21 | from returns.primitives.tracing import collect_traces 22 | 23 | @collect_traces 24 | def function() -> int: 25 | return 0 26 | 27 | reveal_type(function) # N: Revealed type is "def () -> builtins.int" 28 | 29 | - case: collect_traces_decorated_function_with_argument_return_type 30 | disable_cache: false 31 | main: | 32 | from returns.primitives.tracing import collect_traces 33 | 34 | @collect_traces 35 | def function(number: int) -> str: 36 | return str(number) 37 | 38 | reveal_type(function) # N: Revealed type is "def (number: builtins.int) -> builtins.str" 39 | -------------------------------------------------------------------------------- /typesafety/test_result/test_attempt.yml: -------------------------------------------------------------------------------- 1 | - case: attempt_decorator_no_params 2 | disable_cache: false 3 | main: | 4 | from returns.result import attempt 5 | 6 | @attempt 7 | def test() -> int: 8 | return 1 9 | out: | 10 | main:3: error: Argument 1 to "attempt" has incompatible type "Callable[[], int]"; expected "Callable[[_FirstType], int]" [arg-type] 11 | 12 | 13 | - case: attempt_decorator_one_param 14 | disable_cache: false 15 | main: | 16 | from returns.result import attempt 17 | 18 | @attempt 19 | def test(param: str) -> int: 20 | return 1 21 | 22 | reveal_type(test) # N: Revealed type is "def (builtins.str) -> returns.result.Result[builtins.int, builtins.str]" 23 | 24 | def test2(param: int) -> str: 25 | return 'str' 26 | 27 | reveal_type(attempt(test2)) # N: Revealed type is "def (builtins.int) -> returns.result.Result[builtins.str, builtins.int]" 28 | 29 | 30 | - case: attempt_decorator_two_params 31 | disable_cache: false 32 | main: | 33 | from returns.result import attempt 34 | 35 | @attempt 36 | def test(first: str, second: float) -> int: 37 | return 1 38 | out: | 39 | main:3: error: Argument 1 to "attempt" has incompatible type "Callable[[str, float], int]"; expected "Callable[[str], int]" [arg-type] 40 | -------------------------------------------------------------------------------- /typesafety/test_result/test_construct_failure.yml: -------------------------------------------------------------------------------- 1 | - case: failure_lash 2 | disable_cache: false 3 | main: | 4 | from returns.result import Failure, Result 5 | 6 | def returns_result(param: int) -> Result[str, Exception]: 7 | ... 8 | 9 | first: Result[str, int] = Failure(1) 10 | reveal_type(first.lash(returns_result)) # N: Revealed type is "returns.result.Result[builtins.str, builtins.Exception]" 11 | 12 | 13 | - case: failure_alt 14 | disable_cache: false 15 | main: | 16 | from returns.result import Failure 17 | 18 | reveal_type(Failure(1).alt(str)) # N: Revealed type is "returns.result.Result[Any, builtins.str]" 19 | 20 | 21 | - case: failure_failure 22 | disable_cache: false 23 | main: | 24 | from returns.result import Failure 25 | 26 | reveal_type(Failure(1).failure()) # N: Revealed type is "builtins.int" 27 | -------------------------------------------------------------------------------- /typesafety/test_result/test_construct_success.yml: -------------------------------------------------------------------------------- 1 | - case: success_bind 2 | disable_cache: false 3 | main: | 4 | from returns.result import Success, Result 5 | 6 | def returns_result(param: int) -> Result[str, Exception]: 7 | ... 8 | 9 | first: Result[int, Exception] = Success(1) 10 | reveal_type(first.bind(returns_result)) # N: Revealed type is "returns.result.Result[builtins.str, builtins.Exception]" 11 | 12 | 13 | - case: success_bind_result 14 | disable_cache: false 15 | main: | 16 | from returns.result import Success, Result 17 | 18 | def returns_result(param: int) -> Result[str, Exception]: 19 | ... 20 | 21 | first: Result[int, Exception] = Success(1) 22 | reveal_type(first.bind_result(returns_result)) # N: Revealed type is "returns.result.Result[builtins.str, builtins.Exception]" 23 | 24 | 25 | - case: success_map 26 | disable_cache: false 27 | main: | 28 | from returns.result import Success, Result 29 | 30 | reveal_type(Success(1).map(str)) # N: Revealed type is "returns.result.Result[builtins.str, Any]" 31 | 32 | 33 | - case: success_apply1 34 | disable_cache: false 35 | main: | 36 | from returns.result import Success, Result 37 | 38 | reveal_type(Success(1).apply(Success(str))) # N: Revealed type is "returns.result.Result[builtins.str, Any]" 39 | 40 | 41 | - case: success_apply2 42 | disable_cache: false 43 | main: | 44 | from returns.result import Success, Result 45 | from returns.curry import curry 46 | 47 | @curry 48 | def sum_two(first: int, second: float) -> str: 49 | ... 50 | 51 | reveal_type(Success(2.0).apply(Success(1).apply(Success(sum_two)))) # N: Revealed type is "returns.result.Result[builtins.str, Any]" 52 | 53 | 54 | - case: success_value_or 55 | disable_cache: false 56 | main: | 57 | from returns.result import Success 58 | 59 | reveal_type(Success(1).value_or(None)) # N: Revealed type is "Union[builtins.int, None]" 60 | 61 | 62 | - case: success_unwrap 63 | disable_cache: false 64 | main: | 65 | from returns.result import Success 66 | 67 | reveal_type(Success(1).unwrap()) # N: Revealed type is "builtins.int" 68 | -------------------------------------------------------------------------------- /typesafety/test_result/test_result_error.yml: -------------------------------------------------------------------------------- 1 | - case: failure_lash 2 | disable_cache: false 3 | main: | 4 | from returns.result import ResultE, Success, Failure 5 | 6 | def some(arg: int) -> ResultE[int]: 7 | if arg > 0: 8 | return Success(arg) 9 | return Failure(ValueError('test')) 10 | 11 | reveal_type(some(1)) # N: Revealed type is "returns.result.Result[builtins.int, builtins.Exception]" 12 | -------------------------------------------------------------------------------- /typesafety/test_trampolines/test_trampoline.yml: -------------------------------------------------------------------------------- 1 | - case: trampoline_missing_args 2 | disable_cache: false 3 | main: | 4 | from typing import List, Union 5 | from returns.trampolines import Trampoline, trampoline 6 | 7 | @trampoline 8 | def _accumulate( 9 | numbers: List[int], 10 | acc: int = 0, 11 | ) -> Union[int, Trampoline[int]]: 12 | return Trampoline(_accumulate) 13 | out: | 14 | main:9: error: Missing positional argument "numbers" in call to "Trampoline" [call-arg] 15 | 16 | 17 | - case: trampoline_wrong_args 18 | disable_cache: false 19 | main: | 20 | from typing import List, Union 21 | from returns.trampolines import Trampoline, trampoline 22 | 23 | @trampoline 24 | def _accumulate( 25 | numbers: List[int], 26 | acc: int = 0, 27 | ) -> Union[int, Trampoline[int]]: 28 | return Trampoline(_accumulate, ['a'], 'b') 29 | out: | 30 | main:9: error: List item 0 has incompatible type "str"; expected "int" [list-item] 31 | main:9: error: Argument 3 to "Trampoline" has incompatible type "str"; expected "int" [arg-type] 32 | 33 | 34 | - case: trampoline_return_type 35 | disable_cache: false 36 | main: | 37 | from typing import List, Union 38 | from returns.trampolines import Trampoline, trampoline 39 | 40 | @trampoline 41 | def _accumulate( 42 | numbers: List[int], 43 | acc: int = 0, 44 | ) -> Union[int, Trampoline[int]]: 45 | return Trampoline(_accumulate, [1], 2) 46 | 47 | reveal_type(_accumulate([1, 2])) # N: Revealed type is "builtins.int" 48 | -------------------------------------------------------------------------------- /typesafety/test_unsafe/test_unsafe.yml: -------------------------------------------------------------------------------- 1 | - case: unsafe_perform_io 2 | disable_cache: false 3 | main: | 4 | from returns.io import IO 5 | from returns.unsafe import unsafe_perform_io 6 | 7 | reveal_type(unsafe_perform_io(IO(1))) # N: Revealed type is "builtins.int" 8 | --------------------------------------------------------------------------------