👻 Phantom types for Python

Overview

Depiction of phantom types in the wild

phantom-types

CI Build Status Documentation Build Status Test coverage report

Phantom types for Python will help you make illegal states unrepresentable and avoid shotgun parsing by enabling you to practice "Parse, don't validate".

This project is in early development and fundamental changes should be expected. Semantic versioning will be followed after version 1.0, but before that breaking changes might occur between minor versions.

Checkout the complete documentation on Read the Docs →

Installation

$  python3 -m pip install phantom-types

Examples

By introducing a phantom type we can define a pre-condition for a function argument.

from phantom import Phantom
from phantom.predicates.collection import contained


class Name(str, Phantom, predicate=contained({"Jane", "Joe"})):
    ...


def greet(name: Name):
    print(f"Hello {name}!")

Now this will be a valid call.

greet(Name.parse("Jane"))

... and so will this.

joe = "Joe"
assert isinstance(joe, Name)
greet(joe)

But this will yield a static type checking error.

greet("bird")

Runtime type checking

By combining phantom types with a runtime type-checker like beartype or typeguard, we can achieve the same level of security as you'd gain from using contracts.

import datetime
from beartype import beartype
from phantom.datetime import TZAware


@beartype
def soon(dt: TZAware) -> TZAware:
    return dt + datetime.timedelta(seconds=10)

The soon function will now validate that both its argument and return value is timezone aware, e.g. pre- and post conditions.

Pydantic support

Phantom types are ready to use with pydantic and have integrated support out-of-the-box. Subclasses of Phantom work with both pydantic's validation and its schema generation.

class Name(str, Phantom, predicate=contained({"Jane", "Joe"})):
    @classmethod
    def __schema__(cls) -> Schema:
        return super().__schema__() | {
            "description": "Either Jane or Joe",
            "format": "custom-name",
        }


class Person(BaseModel):
    name: Name
    created: TZAware


print(json.dumps(Person.schema(), indent=2))

The code above outputs the following JSONSchema.

{
  "title": "Person",
  "type": "object",
  "properties": {
    "name": {
      "title": "Name",
      "description": "Either Jane or Joe",
      "format": "custom-name",
      "type": "string"
    },
    "created": {
      "title": "TZAware",
      "description": "A date-time with timezone data.",
      "type": "string",
      "format": "date-time"
    }
  },
  "required": ["name", "created"]
}

Development

Install development requirements, preferably in a virtualenv:

$ python3 -m pip install .[test,pydantic,phonenumbers]

Run tests:

$ pytest
# or
$ make test

Linting and static type checking is setup with pre-commit, after installing it you can setup hooks with the following command, so that checks run before you push changes.

# configure hooks to run when pushing
$ pre-commit install -t pre-push
# or when committing
$ pre-commit install -t pre-commit
# run all checks
$ pre-commit run --all-files
# or just a single hook
$ pre-commit run mypy --all-files

In addition to static type checking, the project is setup with pytest-mypy-plugins to test that exposed mypy types work as expected, these checks will run together with the rest of the test suite, but you can single them out with the following command.

$ make test-typing
Comments
  • Reintroduce support for Python 3.7

    Reintroduce support for Python 3.7

    Hi! A quick question:

    Why have you dropped python3.7 support in this commit https://github.com/antonagestam/phantom-types/commit/c0817edd886237d288b277c93a89c04d286e54e1 ?

    Looks like python3.7 was supported not a long time ago: https://github.com/antonagestam/phantom-types/commit/c2e6d37a0afa2a9dd531df016414a12688341006

    From what I can see the only feature of python3.8 you are using is / arguments, which can be easily converted into regular arguments (which is even cleaner in my opinion). Anything else that I've missed?

    enhancement 
    opened by sobolevn 10
  • Fix Mypy errors in strict mode

    Fix Mypy errors in strict mode

    Python program in README.md:

    from phantom import Phantom
    from phantom.predicates.collection import contained
    
    
    class Name(str, Phantom, predicate=contained({"Jane", "Joe"})):
        ...
    
    
    def greet(name: Name):
        print(f"Hello {name}!")
    
    
    greet(Name.parse("Jane"))
    
    joe = "Joe"
    assert isinstance(joe, Name)
    greet(joe)
    
    greet("bird")
    

    Mypy output:

    $ mypy foobar.py --strict                
    foobar.py:5: error: Missing type parameters for generic type "Phantom"
    foobar.py:9: error: Function is missing a return type annotation
    foobar.py:18: error: Argument 1 to "greet" has incompatible type "str"; expected "Name"
    Found 3 errors in 1 file (checked 1 source file)
    
    opened by maggyero 6
  • Improves docs a bit

    Improves docs a bit

    1. Adds links to types that we are talking about
    2. Adds .. code-block:: python in all places, otherwise this code was not highlighted on github

    I really hope that RTD will build my PR to test it out, I am too lazy to test it locally 😆

    opened by sobolevn 5
  • `mypy` crash due to `CachingProtocolMeta`

    `mypy` crash due to `CachingProtocolMeta`

    I'm suddenly getting this on cached mypy runs ...

    Traceback (most recent call last):
      File "/app/venv/bin/mypy", line 8, in <module>
        sys.exit(console_entry())
      File "/app/venv/lib/python3.10/site-packages/mypy/__main__.py", line 15, in console_entry
        main()
      File "/app/venv/lib/python3.10/site-packages/mypy/main.py", line 95, in main
        res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
      File "/app/venv/lib/python3.10/site-packages/mypy/main.py", line 174, in run_build
        res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
      File "/app/venv/lib/python3.10/site-packages/mypy/build.py", line 193, in build
        result = _build(
      File "/app/venv/lib/python3.10/site-packages/mypy/build.py", line 276, in _build
        graph = dispatch(sources, manager, stdout)
      File "/app/venv/lib/python3.10/site-packages/mypy/build.py", line 2903, in dispatch
        process_graph(graph, manager)
      File "/app/venv/lib/python3.10/site-packages/mypy/build.py", line 3280, in process_graph
        process_fresh_modules(graph, prev_scc, manager)
      File "/app/venv/lib/python3.10/site-packages/mypy/build.py", line 3361, in process_fresh_modules
        graph[id].fix_cross_refs()
      File "/app/venv/lib/python3.10/site-packages/mypy/build.py", line 2112, in fix_cross_refs
        fixup_module(self.tree, self.manager.modules, self.options.use_fine_grained_cache)
      File "/app/venv/lib/python3.10/site-packages/mypy/fixup.py", line 53, in fixup_module
        node_fixer.visit_symbol_table(tree.names, tree.fullname)
      File "/app/venv/lib/python3.10/site-packages/mypy/fixup.py", line 125, in visit_symbol_table
        self.visit_type_info(value.node)
      File "/app/venv/lib/python3.10/site-packages/mypy/fixup.py", line 87, in visit_type_info
        info.declared_metaclass.accept(self.type_fixer)
      File "/app/venv/lib/python3.10/site-packages/mypy/types.py", line 1283, in accept
        return visitor.visit_instance(self)
      File "/app/venv/lib/python3.10/site-packages/mypy/fixup.py", line 196, in visit_instance
        inst.type = lookup_fully_qualified_typeinfo(
      File "/app/venv/lib/python3.10/site-packages/mypy/fixup.py", line 337, in lookup_fully_qualified_typeinfo
        assert (
    AssertionError: Should never get here in normal mode, got Var:phantom._utils.types.CachingProtocolMeta instead of TypeInfo
    

    Seems to be an issue with CachingProtocolMeta meta class being exposed as Any when looking at the mypy cache ...

    {
        "CachingProtocolMeta": {
            ".class": "SymbolTableNode",
            "kind": "Gdef",
            "module_hidden": true,
            "module_public": false,
            "node": {
                ".class": "Var",
                "flags": [
                    "is_suppressed_import",
                    "is_ready",
                    "is_inferred"
                ],
                "fullname": "phantom._utils.types.CachingProtocolMeta",
                "name": "CachingProtocolMeta",
                "type": {
                    ".class": "AnyType",
                    "missing_import_name": "phantom._utils.types.CachingProtocolMeta",
                    "source_any": null,
                    "type_of_any": 3
                }
            }
        }
    }
    
    opened by lundberg 4
  • Intervals Closed/Open backwards??

    Intervals Closed/Open backwards??

    Hi,

    reading the docs and the code, I feel there's an inversion.

    def open(low: T, high: T) -> Predicate[SupportsLeGe[T]]:
        """
        Create a predicate that succeeds when its argument is in the range ``(low, high)``.
        """
    
        @bind_name(open, low, high)
        def check(value: SupportsLeGe[T]) -> bool:
            return low <= value <= high
    
        return check
    

    Here I would have expected return low < value < high

    https://en.wikipedia.org/wiki/Interval_(mathematics)#Terminology

    In an open interval, bounds are not included, while in a closed one, they are.

    Am I missing something? Am I reading the code wrong?

    bug 
    opened by g-as 4
  • `NonEmpty[str]` type cannot be used as sorting key

    `NonEmpty[str]` type cannot be used as sorting key

    Not sure if I'm using NonEmpty incorrectly here with str. But the code below does not typecheck, and I think it should? (Since the underlying data type is a string)

    from typing import NamedTuple
    from phantom.sized import NonEmpty
    
    
    class X(NamedTuple):
        value: NonEmpty[str]
    
    sorted(
        [X(value=NonEmpty[str].parse("first")), X(value=NonEmpty[str].parse("second"))],
        key=lambda x: x.value
    )
    

    Results in the following error

    10: error: Argument "key" to "sorted" has incompatible type "Callable[[X], NonEmpty[str]]"; expected "Callable[[X], Union[SupportsDunderLT, SupportsDunderGT]]"  [arg-type]
    
    10: error: Incompatible return value type (got "NonEmpty[str]", expected "Union[SupportsDunderLT, SupportsDunderGT]")  [return-value]
    
    opened by flaeppe 4
  • AttributeError: 'operator.attrgetter' object has no attribute '__qualname__'

    AttributeError: 'operator.attrgetter' object has no attribute '__qualname__'

    >>> compose2(print, attrgetter("a.b"))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/anton/.pyenv/versions/gina-api/lib/python3.9/site-packages/phantom/fn.py", line 26, in compose2
        b_name = _name(b)
      File "/Users/anton/.pyenv/versions/gina-api/lib/python3.9/site-packages/phantom/fn.py", line 9, in _name
        return fn.__qualname__
    AttributeError: 'operator.attrgetter' object has no attribute '__qualname__'
    

    This should fall back to __name__ and when that doesn't exist either, should fall back to __str__().

    bug good first issue 
    opened by antonagestam 4
  • Integrate numerary to gain support for numeric tower

    Integrate numerary to gain support for numeric tower

    Closes #34.

    @posita Thanks for pointing me towards your library, it seems to work like a charm! 🙏

    A question: is it correctly interpreted that the type argument to RealLike is whatever the type returns for round() and abs()? Does it make sense to use RealLike[IntegralLike[int]] like I've done?

    I ran into one issue in that I get metaclass conflicts when using RealLike as a bound for a python type, but it should be possible to resolve that (I think). It's been brought up here earlier that it could be nice to provide helper functions for resolving metaclass conflicts, I'm now leaning towards going in that direction.

    opened by antonagestam 3
  • Usage with other types with metaclasses / metaclass conflicts

    Usage with other types with metaclasses / metaclass conflicts

    While working on #123 and solving a metaclass conflict, I was wondering about potential usage of phantom together with django / sqlalchemy projects that make a heavy use of metaclasses.

    For example, this code will produce a metaclass conflict:

    from django.db import models
    
    class  User(models.Model):
        is_paid = models.BooleanField(default=False)
    
    def is_paid_user(value: object) -> bool:
        return isinstance(value, User) and value.is_paid
    
    class PaidUser(User, Phantom, predicate=is_paid_user):
        ...  # metaclass conflict
    

    Is there any simple way to support this? We can probably ship some util metaclass solver like the one from here: https://stackoverflow.com/a/41266737/4842742

    Or at least we can document how to solve this.

    documentation help wanted 
    opened by sobolevn 3
  • `UK` not accepted as a `CountryCode`

    `UK` not accepted as a `CountryCode`

    I know the official alpha-2 code is GB and UK is part of the "exceptional reservations" list of iso3166-1 alpha-2, but frankly, all addresses in Great Britain have a post code of UK.

    I think it could be useful to include UK as well, in cases where one wants to use e.g. country: CountryCode for address validation or the like.

    enhancement 
    opened by flaeppe 2
  • Trying to set up local development, but can't run YAML tests

    Trying to set up local development, but can't run YAML tests

    Hi! I heard about this library from typing-sig and it looks really interesting. I tried setting up local development and ran into a couple issues.

    1. When I run pre-commit run --all, there's a flake8 error:
    (env) ➜  phantom-types git:(main) ✗ pre-commit run --all
    Check for case conflicts.................................................Passed
    Check for merge conflicts................................................Passed
    Fix End of Files.........................................................Passed
    Trim Trailing Whitespace.................................................Passed
    Debug Statements (Python)................................................Passed
    Detect Private Key.......................................................Passed
    pyupgrade................................................................Passed
    autoflake................................................................Passed
    isort....................................................................Passed
    black....................................................................Passed
    blacken-docs.............................................................Passed
    flake8...................................................................Failed
    - hook id: flake8
    - exit code: 1
    
    src/phantom/fn.py:36:9: B018 Found useless expression. Either assign it to a variable or remove it.
    
    Validate GitHub Workflows................................................Passed
    mypy.....................................................................Passed
    check-manifest...........................................................Passed
    format-readme............................................................Failed
    - hook id: format-readme
    - exit code: 1
    
    Executable `docker` not found
    
    (env) ➜  phantom-types git:(main) ✗
    

    And indeed, looking at line 36 of that file shows an unassigned string expression. I assume this is just leftover since that line hasn't been touched since April, but maybe I'm misunderstanding.

    1. Running make test and/or pytest fails on all of the yaml-based tests. Here's an example:
    (env) ➜  phantom-types git:(main) ✗ pytest tests/ext/test_phonenumbers.yaml
    ============================================================================== test session starts ==============================================================================
    platform darwin -- Python 3.9.9, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: /Users/tushar/code/phantom-types, configfile: pyproject.toml
    plugins: mypy-plugins-1.9.2, typeguard-2.13.3
    collected 3 items
    
    tests/ext/test_phonenumbers.yaml FFF                                                                                                                                      [100%]
    
    =================================================================================== FAILURES ====================================================================================
    _____________________________________________________________________________ bound_is_not_subtype ______________________________________________________________________________
    /Users/tushar/code/phantom-types/tests/ext/test_phonenumbers.yaml:9:
    E   pytest_mypy_plugins.utils.TypecheckAssertionError: Invalid output:
    E   Actual:
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:53: error: Unused "type: ignore[misc]" comment (diff)
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:144: error: ClassVar cannot contain type variables  [misc] (diff)
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:162: error: Unused "type: ignore" comment (diff)
    E     main:7: error: Argument 1 to "takes_phone_number" has incompatible type "str"; expected "PhoneNumber"  [arg-type] (diff)
    E     main:12: error: Argument 1 to "takes_formatted_phone_number" has incompatible type "str"; expected "FormattedPhoneNumber"  [arg-type] (diff)
    E   Expected:
    E     main:7: error: Argument 1 to "takes_phone_number" has incompatible type "str"; expected "PhoneNumber"  [arg-type] (diff)
    E     main:12: error: Argument 1 to "takes_formatted_phone_number" has incompatible type "str"; expected "FormattedPhoneNumber"  [arg-type] (diff)
    E   Alignment of first line difference:
    E     E: main:7: error: Argument 1 to "takes_phone_number" has incompatible type ...
    E     A: ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:53: e...
    E        ^
    ________________________________________________________________________________ can_instantiate ________________________________________________________________________________
    /Users/tushar/code/phantom-types/tests/ext/test_phonenumbers.yaml:16:
    E   pytest_mypy_plugins.utils.TypecheckAssertionError: Output is not expected:
    E   Actual:
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:53: error: Unused "type: ignore[misc]" comment (diff)
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:144: error: ClassVar cannot contain type variables  [misc] (diff)
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:162: error: Unused "type: ignore" comment (diff)
    E   Expected:
    E     (empty)
    ___________________________________________________________________________________ can_infer ___________________________________________________________________________________
    /Users/tushar/code/phantom-types/tests/ext/test_phonenumbers.yaml:30:
    E   pytest_mypy_plugins.utils.TypecheckAssertionError: Output is not expected:
    E   Actual:
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:53: error: Unused "type: ignore[misc]" comment (diff)
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:144: error: ClassVar cannot contain type variables  [misc] (diff)
    E     ../../../../../../Users/tushar/code/phantom-types/src/phantom/base:162: error: Unused "type: ignore" comment (diff)
    E   Expected:
    E     (empty)
    ============================================================================ short test summary info ============================================================================
    FAILED tests/ext/test_phonenumbers.yaml::bound_is_not_subtype -
    FAILED tests/ext/test_phonenumbers.yaml::can_instantiate -
    FAILED tests/ext/test_phonenumbers.yaml::can_infer -
    =============================================================================== 3 failed in 0.81s ===============================================================================
    (env) ➜  phantom-types git:(main) ✗
    

    It looks to me like every test is throwing errors on lines 53, 144, and 162 of src/phantom/base.py, e.g., here. If I run mypy ., the same errors appear in the output there.

    The first test example (bound_is_not_subtype) shows that I am getting the expected results, but every test has these three extra errors appended to it. I assume this is a difference in mypy config that I'm missing, but I'd love help figuring this out.

    Thanks for your great work on this library!

    opened by tuchandra 2
  • Support for hypothesis

    Support for hypothesis

    I currently wanted to add hypothesis to my tests and I use phantom types in my pydantic models. Hypothesis has built-in support for pydantic, but it turns out it does not work with phantom types.

    from phantom.interval import Open
    from hypothesis import given, strategies as st
    from pydantic import BaseModel
    
    
    class Int0To10(int, Open, low=0, high=10):
        ...
    
    # st.register_type_strategy(Int0To10, st.integers(0, 10))
    
    class MySchema(BaseModel):
        val: Int0To10
    
    @given(st.builds(MySchema))
    def test_schema(instance):
        print(instance.json(indent=2))
    
    test_schema()
    

    results in

    Traceback (most recent call last):
      File "/local/home/a.pirogov/.cache/pypoetry/virtualenvs/metador-core-AXME58BY-py3.8/lib/python3.8/site-packages/hypothesis/strategies/_internal/core.py", line 836, in do_draw
        return self.target(
    TypeError: __call__() missing 1 required positional argument: 'instance'
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "scratch_hypo.py", line 24, in <module>
        test_schema()
      File "scratch_hypo.py", line 20, in test_schema
        def test_schema(instance):
      File "/local/home/a.pirogov/.cache/pypoetry/virtualenvs/metador-core-AXME58BY-py3.8/lib/python3.8/site-packages/hypothesis/core.py", line 1325, in wrapped_test
        raise the_error_hypothesis_found
      File "/local/home/a.pirogov/.cache/pypoetry/virtualenvs/metador-core-AXME58BY-py3.8/lib/python3.8/site-packages/hypothesis/strategies/_internal/core.py", line 855, in do_draw
        raise InvalidArgument(
    hypothesis.errors.InvalidArgument: Calling <class '__main__.Int0To10'> with no arguments raised an error - try using from_type(<class '__main__.Int0To10'>) instead of builds(<class '__main__.Int0To10'>)
    

    but works when registering the type strategy (line in example is uncommented)

    Would it be possible to register the corresponding generating strategies for all built-in types and provide a hook like __hypothesis_strategy__ where an automatic strategy is not feasible / to override the default one?

    I think that probably should be done in the metaclass, so the strategy is registered whenever a type is defined and hypothesis is installed in the environment.

    enhancement 
    opened by apirogov 2
  • Use GIthub Pages for code coverage and docs

    Use GIthub Pages for code coverage and docs

    See draft PR: https://github.com/antonagestam/phantom-types/pull/257

    The preview feature is not yet available: https://github.com/antonagestam/phantom-types/blob/18a79f6662399ce970fb10422e86a1312cf86252/.github/workflows/docs.yaml#L54

    Once it is, will open up to some nice workflows and not having to depend on external services for these things.

    blocked 
    opened by antonagestam 0
  • Replacing `tzinfo=None` still considered TZAware

    Replacing `tzinfo=None` still considered TZAware

    from phantom.datetime import TZAware
    import datetime
    
    t = TZAware.parse(datetime.datetime.now(tz=datetime.timezone.utc))
    u = t.replace(tzinfo=None)
    reveal_type(u)  # -> TZAware
    
    opened by aiven-anton 0
  • feat: class docstring overrides default description from __schema__

    feat: class docstring overrides default description from __schema__

    fixes #238

    I do it in __modify_schema__, so that the docstring, if present, is applied last and not first (which would be the case when just adding it in __schema__)

    opened by apirogov 6
Releases(1.1.0)
  • 1.1.0(Nov 17, 2022)

    • Support Python 3.11 final by @antonagestam in https://github.com/antonagestam/phantom-types/pull/242
    • Remove ignored typing error of import of CachingProtocolMeta by @flaeppe in https://github.com/antonagestam/phantom-types/pull/244
    • Drop dependency on ammaraskar/sphinx-action by @antonagestam in https://github.com/antonagestam/phantom-types/pull/247

    Full Changelog: https://github.com/antonagestam/phantom-types/compare/1.0.0...v1.1.0

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Sep 24, 2022)

    Breaking changes

    There are two breaking changes in this release. Because interval types and predicate functions were incorrectly named, they have been renamed to use the terms inclusive/exclusive instead of closed/open. Renaming them has the benefit that more breakage downstream should be discovered in earlier stages, e.g. in test suites and at import-time, instead of breaking at runtime in production environments.

    A parse method has been implemented for TZAware and TZNaive using python-dateutil. When python-dateutil is not installed and the parse methods are called with strings, they now raise MissingDependency.

    What's changed

    • Make datetime.tzinfo non-optional for TZAware by @antonagestam in https://github.com/antonagestam/phantom-types/pull/233
    • Give parsing ability to datetime types by @antonagestam in https://github.com/antonagestam/phantom-types/pull/234
    • Fixed open/closed interval definitions by @g-as in https://github.com/antonagestam/phantom-types/pull/232

    New Contributors

    • @g-as made their first contribution in https://github.com/antonagestam/phantom-types/pull/232

    Full Changelog: https://github.com/antonagestam/phantom-types/compare/0.18.0...1.0.0

    Source code(tar.gz)
    Source code(zip)
  • 0.18.0(Sep 18, 2022)

    What's Changed

    • Canonicalize mutable bound check by @antonagestam in https://github.com/antonagestam/phantom-types/pull/224
    • Introduce PhantomBound and NonEmptyStr by @antonagestam in https://github.com/antonagestam/phantom-types/pull/193
    • Drop workaround for fixed 3.11 issue (see #220) by @antonagestam in https://github.com/antonagestam/phantom-types/pull/228

    Full Changelog: https://github.com/antonagestam/phantom-types/compare/v0.17.1...0.18.0

    Source code(tar.gz)
    Source code(zip)
  • v0.17.1(Jul 6, 2022)

    New features

    • Support Python 3.11 https://github.com/antonagestam/phantom-types/pull/220 https://github.com/antonagestam/phantom-types/pull/221

    Full Changelog: https://github.com/antonagestam/phantom-types/compare/v0.17.0...v0.17.1

    Source code(tar.gz)
    Source code(zip)
  • v0.17.0(Jul 6, 2022)

    New features

    • Use narrower types in predicates and bounds by @antonagestam in https://github.com/antonagestam/phantom-types/pull/218

    Fixed

    • Fix broken docstring function references by @antonagestam in https://github.com/antonagestam/phantom-types/pull/204
    • Pin numerary on Python 3.7 by @antonagestam in https://github.com/antonagestam/phantom-types/pull/213

    Meta

    • Add .editorconfig pre-commit check by @antonagestam in https://github.com/antonagestam/phantom-types/pull/205
    • Add project URLs to setup.cfg by @antonagestam in https://github.com/antonagestam/phantom-types/pull/212
    • Remove duplicate section in docs by @antonagestam in https://github.com/antonagestam/phantom-types/pull/208
    • Make base modules private by @antonagestam in https://github.com/antonagestam/phantom-types/pull/215
    • Bump pre-commit hooks by @antonagestam in https://github.com/antonagestam/phantom-types/pull/216
    • Run test suite on Python 3.11 by @antonagestam in https://github.com/antonagestam/phantom-types/pull/217

    Full Changelog: https://github.com/antonagestam/phantom-types/compare/0.16.0...v0.17.0

    Source code(tar.gz)
    Source code(zip)
  • 0.16.0(Mar 30, 2022)

    What's Changed

    • Explode partials in reprs by @antonagestam in https://github.com/antonagestam/phantom-types/pull/191
    • Remove instability notice by @antonagestam in https://github.com/antonagestam/phantom-types/pull/192
    • Introduce SequenceNotStr by @antonagestam in https://github.com/antonagestam/phantom-types/pull/194
    • Add minLength/maxLength to Schema by @antonagestam in https://github.com/antonagestam/phantom-types/pull/198

    Full Changelog: https://github.com/antonagestam/phantom-types/compare/0.15.1...0.16.0

    Source code(tar.gz)
    Source code(zip)
  • 0.15.0(Jan 22, 2022)

  • 0.14.0(Nov 28, 2021)

  • 0.13.0(Sep 25, 2021)

    • Remove deprecated phantom.ext.iso3166 (#152)
    • Raise an error for known mutable bounds. Subclassing from Phantom now raises MutableType if the bound type is known to be mutable, e.g. list, set, dict and unfrozen dataclasses will all raise an error. (#156)
    Source code(tar.gz)
    Source code(zip)
  • 0.12.0(Sep 24, 2021)

    Added

    • Improved __repr__ for predicate factories (#148)
    • Introduce src directory layout, to make tests run against an installed version of the library (#149)
    • Make CountryCode a union of a Literal and a phantom type. This gets rid of the external dependency on the iso3166 package for country code support and moves the country code support into phantom.iso3166. The old module is still importable but yields a deprecation warning and will be removed in 0.13.0. (#136)
    Source code(tar.gz)
    Source code(zip)
  • 0.11.0(Sep 24, 2021)

    Added

    • Expose and document the @excepts decorator (#142). This decorator wasn't documented and therefor not previously supported, however this change moves the decorator from phantom.utils to phantom.fn so code that depended on this private function will now how to update imports.
    • Enable blacken-docs for formatting example code (#141)

    Fixed

    • Don't expect callables to have __qualname__ (#143)
    • Make Interval parse strings (#145)
    Source code(tar.gz)
    Source code(zip)
Easy saving and switching between multiple KDE configurations.

Konfsave Konfsave is a config manager. That is, it allows you to save, back up, and easily switch between different (per-user) system configurations.

42 Sep 25, 2022
Type annotations builder for boto3 compatible with VSCode, PyCharm, Emacs, Sublime Text, pyright and mypy.

mypy_boto3_builder Type annotations builder for boto3-stubs project. Compatible with VSCode, PyCharm, Emacs, Sublime Text, mypy, pyright and other too

Vlad Emelianov 2 Dec 05, 2022
Check for python builtins being used as variables or parameters

Flake8 Builtins plugin Check for python builtins being used as variables or parameters. Imagine some code like this: def max_values(list, list2):

Gil Forcada Codinachs 98 Jan 08, 2023
Tool to automatically fix some issues reported by flake8 (forked from autoflake).

autoflake8 Introduction autoflake8 removes unused imports and unused variables from Python code. It makes use of pyflakes to do this. autoflake8 also

francisco souza 27 Sep 08, 2022
A framework for detecting, highlighting and correcting grammatical errors on natural language text.

Gramformer Human and machine generated text often suffer from grammatical and/or typographical errors. It can be spelling, punctuation, grammatical or

Prithivida 1.3k Jan 08, 2023
mypy plugin to type check Kubernetes resources

kubernetes-typed mypy plugin to dynamically define types for Kubernetes objects. Features Type checking for Custom Resources Type checking forkubernet

Artem Yarmoliuk 16 Oct 10, 2022
A plugin for Flake8 that provides specializations for type hinting stub files

flake8-pyi A plugin for Flake8 that provides specializations for type hinting stub files, especially interesting for linting typeshed. Functionality A

Łukasz Langa 58 Jan 04, 2023
Design by contract for Python. Write bug-free code. Add a few decorators, get static analysis and tests for free.

A Python library for design by contract (DbC) and checking values, exceptions, and side-effects. In a nutshell, deal empowers you to write bug-free co

Life4 473 Dec 28, 2022
flake8 plugin that integrates isort

Flake8 meet isort Use isort to check if the imports on your python files are sorted the way you expect. Add an .isort.cfg to define how you want your

Gil Forcada Codinachs 139 Nov 08, 2022
Plugin for mypy to support zope.interface

Plugin for mypy to support zope.interface The goal is to be able to make zope interfaces to be treated as types in mypy sense. Usage Install both mypy

Shoobx 36 Oct 29, 2022
Flake8 plugin for managing type-checking imports & forward references

flake8-type-checking Lets you know which imports to put in type-checking blocks. For the imports you've already defined inside type-checking blocks, i

snok 67 Dec 16, 2022
Collection of awesome Python types, stubs, plugins, and tools to work with them.

Awesome Python Typing Collection of awesome Python types, stubs, plugins, and tools to work with them. Contents Static type checkers Dynamic type chec

TypedDjango 1.2k Jan 04, 2023
Reference implementation of sentinels for the Python stdlib

Sentinels This is a reference implementation of a utility for the definition of sentinel values in Python. This also includes a draft PEP for the incl

Tal Einat 22 Aug 27, 2022
An open-source, mini imitation of GitHub Copilot for Emacs.

Second Mate An open-source, mini imitation of GitHub Copilot using EleutherAI GPT-Neo-2.7B (via Huggingface Model Hub) for Emacs. This is a much small

Sam Rawal 238 Dec 27, 2022
A simple program which checks Python source files for errors

Pyflakes A simple program which checks Python source files for errors. Pyflakes analyzes programs and detects various errors. It works by parsing the

Python Code Quality Authority 1.2k Dec 30, 2022
Automated security testing using bandit and flake8.

flake8-bandit Automated security testing built right into your workflow! You already use flake8 to lint all your code for errors, ensure docstrings ar

Tyler Wince 96 Jan 01, 2023
Tool to check the completeness of MANIFEST.in for Python packages

check-manifest Are you a Python developer? Have you uploaded packages to the Python Package Index? Have you accidentally uploaded broken packages with

Marius Gedminas 270 Dec 26, 2022
👻 Phantom types for Python

phantom-types Phantom types for Python will help you make illegal states unrepresentable and avoid shotgun parsing by enabling you to practice "Parse,

Anton Agestam 118 Dec 22, 2022
The official GitHub mirror of https://gitlab.com/pycqa/flake8

Flake8 Flake8 is a wrapper around these tools: PyFlakes pycodestyle Ned Batchelder's McCabe script Flake8 runs all the tools by launching the single f

Python Code Quality Authority 2.6k Jan 03, 2023
Performant type-checking for python.

Pyre is a performant type checker for Python compliant with PEP 484. Pyre can analyze codebases with millions of lines of code incrementally – providi

Facebook 6.2k Jan 04, 2023