Skip to main content

A Python library for creating and managing new types with enhanced type safety and flexibility.

Project description

python-newtype

Documentation

docs passing

Compatibility and Version

Python compat PyPi

CI/CD

Coverage

License and Issues

License Issues Closed Issues Open Issues

Development and Quality

Forks Stars Downloads Contributors Commits Last Commit Code Size Repo Size Watchers Activity PRs Merged PRs Open PRs

A powerful Python library for extending existing types with additional functionality while preserving their original behavior, type information and subtype invariances.

Features

  • Type Wrapping: Seamlessly wrap existing Python types with new functionality and preservation of subtype invariances when using methods of supertype
  • Custom Initialization: Control object initialization with special handling
  • Attribute Preservation: Maintains both __dict__ and __slots__ attributes
  • Memory Efficient: Uses weak references for caching
  • Debug Support: Built-in debug printing capabilities for development
  • Async Support: Full support for asynchronous methods and operations

Quick Start

Installation

pip install python-newtype

Basic Usage

import pytest
import re
from newtype import NewType, newtype_exclude


class EmailStr(NewType(str)):
    # you can define `__slots__` to save space
    __slots__ = (
        '_local_part',
        '_domain_part',
    )

    def __init__(self, value: str):
        super().__init__()
        if "@" not in value:
            raise TypeError("`EmailStr` requires a '@' symbol within")
        self._local_part, self._domain_part = value.split("@")

    @newtype_exclude
    def __str__(self):
        return f"<Email - Local Part: {self.local_part}; Domain Part: {self.domain_part}>"

    @property
    def local_part(self):
        """Return the local part of the email address."""
        return self._local_part

    @property
    def domain_part(self):
        """Return the domain part of the email address."""
        return self._domain_part

    @property
    def full_email(self):
        """Return the full email address."""
        return str(self)

    @classmethod
    def from_string(cls, email: str):
        """Create an EmailStr instance from a string."""
        return cls(email)

    @staticmethod
    def is_valid_email(email: str) -> bool:
        """Check if the provided string is a valid email format."""
        email_regex = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
        return re.match(email_regex, email) is not None


def test_emailstr_replace():
    """`EmailStr` uses `str.replace(..)` as its own method, returning an instance of `EmailStr`
    if the resultant `str` instance is a value `EmailStr`.
    """
    peter_email = EmailStr("peter@gmail.com")
    smith_email = EmailStr("smith@gmail.com")

    with pytest.raises(Exception):
        # this raises because `peter_email` is no longer an instance of `EmailStr`
        peter_email = peter_email.replace("peter@gmail.com", "petergmail.com")

    # this works because the entire email can be 'replaced'
    james_email = smith_email.replace("smith@gmail.com", "james@gmail.com")

    # comparison with `str` is built-in
    assert james_email == "james@gmail.com"

    # `james_email` is still an `EmailStr`
    assert isinstance(james_email, EmailStr)

    # this works because the local part can be 'replaced'
    jane_email = james_email.replace("james", "jane")

    # `jane_email` is still an `EmailStr`
    assert isinstance(jane_email, EmailStr)
    assert jane_email == "jane@gmail.com"


def test_emailstr_properties_methods():
    """Test the property, class method, and static method of EmailStr."""
    # Test property
    email = EmailStr("test@example.com")
    # `property` is not coerced to `EmailStr`
    assert email.full_email == "<Email - Local Part: test; Domain Part: example.com>"
    assert isinstance(email.full_email, str)
    # `property` is not coerced to `EmailStr`
    assert not isinstance(email.full_email, EmailStr)
    assert email.local_part == "test"
    assert email.domain_part == "example.com"

    # Test class method
    email_from_string = EmailStr.from_string("classmethod@example.com")
    # `property` is not coerced to `EmailStr`
    assert (
        email_from_string.full_email
        == "<Email - Local Part: classmethod; Domain Part: example.com>"
    )
    assert email_from_string.local_part == "classmethod"
    assert email_from_string.domain_part == "example.com"

    # Test static method
    assert EmailStr.is_valid_email("valid.email@example.com") is True
    assert EmailStr.is_valid_email("invalid-email.com") is False


def test_email_str__slots__():
    email = EmailStr("test@example.com")

    with pytest.raises(AttributeError):
        email.hi = "bye"
        assert email.hi == "bye"

Documentation

For detailed documentation, visit py-nt.asyncmove.com.

Key Topics:

Development

Prerequisites

  • Python 3.8 or higher
  • C compiler (for building extensions)
  • Development packages:
    make install-dev-deps
    

Building from Source

git clone https://github.com/jymchng/python-newtype-dev.git
cd python-newtype-dev
make build

Install from Source

git clone https://github.com/jymchng/python-newtype-dev.git
cd python-newtype-dev
make install

Running Tests

# Run all tests
make test

# Run with debug output
make test-debug

# Run specific test suite
make test-custom

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Special thanks to all contributors who have helped shape this project.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_newtype-0.1.6.tar.gz (24.3 kB view details)

Uploaded Source

Built Distributions

python_newtype-0.1.6-cp312-cp312-win_amd64.whl (36.0 kB view details)

Uploaded CPython 3.12Windows x86-64

python_newtype-0.1.6-cp312-cp312-manylinux_2_39_x86_64.whl (58.1 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.39+ x86-64

python_newtype-0.1.6-cp312-cp312-macosx_14_0_arm64.whl (36.8 kB view details)

Uploaded CPython 3.12macOS 14.0+ ARM64

python_newtype-0.1.6-cp311-cp311-win_amd64.whl (35.8 kB view details)

Uploaded CPython 3.11Windows x86-64

python_newtype-0.1.6-cp311-cp311-manylinux_2_39_x86_64.whl (55.2 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.39+ x86-64

python_newtype-0.1.6-cp311-cp311-macosx_14_0_arm64.whl (36.6 kB view details)

Uploaded CPython 3.11macOS 14.0+ ARM64

python_newtype-0.1.6-cp310-cp310-win_amd64.whl (35.8 kB view details)

Uploaded CPython 3.10Windows x86-64

python_newtype-0.1.6-cp310-cp310-manylinux_2_39_x86_64.whl (54.6 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.39+ x86-64

python_newtype-0.1.6-cp310-cp310-macosx_14_0_arm64.whl (36.6 kB view details)

Uploaded CPython 3.10macOS 14.0+ ARM64

python_newtype-0.1.6-cp39-cp39-win_amd64.whl (35.8 kB view details)

Uploaded CPython 3.9Windows x86-64

python_newtype-0.1.6-cp39-cp39-manylinux_2_39_x86_64.whl (54.2 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.39+ x86-64

python_newtype-0.1.6-cp39-cp39-macosx_14_0_arm64.whl (36.6 kB view details)

Uploaded CPython 3.9macOS 14.0+ ARM64

python_newtype-0.1.6-cp38-cp38-win_amd64.whl (35.8 kB view details)

Uploaded CPython 3.8Windows x86-64

python_newtype-0.1.6-cp38-cp38-manylinux_2_39_x86_64.whl (56.6 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.39+ x86-64

python_newtype-0.1.6-cp38-cp38-macosx_14_0_arm64.whl (36.8 kB view details)

Uploaded CPython 3.8macOS 14.0+ ARM64

File details

Details for the file python_newtype-0.1.6.tar.gz.

File metadata

  • Download URL: python_newtype-0.1.6.tar.gz
  • Upload date:
  • Size: 24.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for python_newtype-0.1.6.tar.gz
Algorithm Hash digest
SHA256 718e71da617ce03eb444b6e91ec57754eda937c4e4c2574f3914badde3ef610d
MD5 770e43519d95d3ee45062e4fd1bffece
BLAKE2b-256 6fdd6f498d68dc811a603b951c5a2edb9f0ee8cc6b8bca185a72fd6c60f80007

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 fee3809d85f67b42adbe248526398e031512c189d9a2ffb371c0121076bcfa94
MD5 c1934dcf2d7671e0d12b75f05905af22
BLAKE2b-256 8166c1aab886dc1e1b82e413c91d96973d7aa69a8e2b8e06b2e35bf788f5fa04

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp312-cp312-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp312-cp312-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 506742d216a48f1920ad5b9a5b5fc29928a7998d6e470f70ddec2076b605c974
MD5 20cb5dd3894a121520fd06270a49a5d8
BLAKE2b-256 8f3bcc9b56b98e4d6beed08aba636edec2ce9282af8f11535fe8ebbe11df880d

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp312-cp312-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp312-cp312-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 b0e245ee236900392b4b7c18aac1cfc8fcb833ca6c9ac7550168e494eeb01d80
MD5 d9ba93f7ec2335cd2732040c84fe45c8
BLAKE2b-256 4b94b52177c918b67d4a13bc84b67771e0c8a1ccb785211dcffd32b7bf3b5e3b

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 80160d431ba1562a0e5034f48c647ebe08613102555be879afb6d3696266efc0
MD5 fd2973a650892cc07446de2efc1ef784
BLAKE2b-256 1816661ca9fdb132f0ebaf9eca6448cdcce2e2463009a439250eedb52cd2c021

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp311-cp311-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp311-cp311-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 00784ebd3eee89ea9903af7bfa46ebb195c301174cc5645b32c968562e94df81
MD5 33f879f7d1624c166e3cece77f4a056c
BLAKE2b-256 13724d26df4357dbd52ae747812555f51246dc8215fb3a1b9ab23732410d0297

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp311-cp311-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp311-cp311-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 e7bbe331611d7b540cea8ca9c87c46c0a38206ead96d7a2034e5dad95cd3a085
MD5 f5531227b78cb807ee45d9f93b9b66ed
BLAKE2b-256 d232d5b385b55b5fd9524bc8227dfacab4f31952da5b7ae45422c72a979be95d

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 a91111a744420e27eed7070e108dd0951de99ad9176d3ac5d3a067d83bfa13d0
MD5 9826dc24983a0383038b9e409617ccf8
BLAKE2b-256 1e7e3512197616583e6e940f6c282cbd4b9c49c39cd606564e566fc3299c72df

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp310-cp310-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp310-cp310-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 81460fb11f02abe3c4bc5a1ea6b5c55a1eb785063caa9cfc170468efacfe479d
MD5 130ead7bb05281eb2fa96aeed0a53404
BLAKE2b-256 38c6051f3a6b01497492bd271d46dad3ef990646ffc7edc43d7250717be63b25

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp310-cp310-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp310-cp310-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 30c035a309b16ca77a1e30e0a2465023fef34c7e1eadbcc369f50930c17ad0e5
MD5 cecc78cacccc026c321801c1d65804c6
BLAKE2b-256 14ff963a870166ad86e8f35563e26bb734e8a213ecee0e5775bd7dbc3c561796

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp39-cp39-win_amd64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 461face6ce8c455b89fb66580eb9d7118c5ff74f060663cf635b9abed03e5fc0
MD5 4b2770e649bee98bc63f6f4c698f37cc
BLAKE2b-256 99a0a68d6373b49277f6baf3f73d69918fdac9cbc09aeff4df08dd8521fcd48f

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp39-cp39-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp39-cp39-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 18bb0973f91e7807a6d4ea6dc742884902c4b12036dce29d30697fa347bbb4f8
MD5 cd29caf6e06e8d6a93ed89966d5e860a
BLAKE2b-256 757f65e08a6c2b938c722fd27984e661d6eaa1bde44a589e7bf5876425dbcc46

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp39-cp39-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp39-cp39-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 c625ae907301e2db392bffef36c657f144802476fca1b3860e292af451bd0552
MD5 6f9ac47a72e338cb09b993703e9189ca
BLAKE2b-256 6e812ffcdeab645ee522fede774304f39f2037e449af1923d506cc42236cbde4

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp38-cp38-win_amd64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 332da8a80c2bad3fd1d68577259f93d7436a8c47c33028e51ad0242aed32c58f
MD5 915e380e05b63e13efede8de8b3b74e6
BLAKE2b-256 b8d5df883963777baef4fab297d9ad3a5897f29dfe82ed8bc92af936114da55f

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp38-cp38-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp38-cp38-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 4f7eb9991c77211ada1bdbff3478c36e3b813f2a02c024fc433cdbb95f9e9ed2
MD5 a27f34651a043e22126b0e031358d982
BLAKE2b-256 ded98fd64b740ed9bf2adae98e1de5e4117fe98c4a4acbebe790c8bc3c192da9

See more details on using hashes here.

File details

Details for the file python_newtype-0.1.6-cp38-cp38-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for python_newtype-0.1.6-cp38-cp38-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 9b4635bda0a81fb5cce3d100ed29ee3f7208cbe01cad7b95dd8f91a24ca7e1f5
MD5 716e539cd03bdf0d9325106ce3f90e5d
BLAKE2b-256 ae881a00a8e5dbad21a864a117a2bfaafd7dd8cd147a689c43b807d58d9267f4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page