{"id":30240457,"url":"https://github.com/jymchng/python-newtype-dev","last_synced_at":"2025-08-15T04:57:19.968Z","repository":{"id":267133357,"uuid":"837993993","full_name":"jymchng/python-newtype-dev","owner":"jymchng","description":"Beautiful way to create new types for your Python classes!","archived":false,"fork":false,"pushed_at":"2025-02-20T08:20:53.000Z","size":57209,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-03T04:08:34.001Z","etag":null,"topics":["classes","newtype","python","python3","types"],"latest_commit_sha":null,"homepage":"https://py-nt.asyncmove.com/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jymchng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-04T16:30:29.000Z","updated_at":"2025-04-24T07:17:36.000Z","dependencies_parsed_at":"2025-01-15T18:13:30.168Z","dependency_job_id":"a0661406-6335-4ecc-839d-92d1e225290c","html_url":"https://github.com/jymchng/python-newtype-dev","commit_stats":null,"previous_names":["jymchng/python-newtype-dev"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/jymchng/python-newtype-dev","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Fpython-newtype-dev","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Fpython-newtype-dev/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Fpython-newtype-dev/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Fpython-newtype-dev/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jymchng","download_url":"https://codeload.github.com/jymchng/python-newtype-dev/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jymchng%2Fpython-newtype-dev/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270524606,"owners_count":24600205,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["classes","newtype","python","python3","types"],"created_at":"2025-08-15T04:57:17.696Z","updated_at":"2025-08-15T04:57:19.959Z","avatar_url":"https://github.com/jymchng.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# python-newtype\n\n## Documentation\n\u003ca href=\"https://py-nt.asyncmove.com\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/docs-passing-brightgreen.svg\" width=\"100\" alt=\"docs passing\"\u003e\n\u003c/a\u003e\n\n### Compatibility and Version\n\u003cimg src=\"https://img.shields.io/badge/%3E=python-3.8-blue.svg\" alt=\"Python compat\"\u003e\n\u003ca href=\"https://pypi.python.org/pypi/python-newtype\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/python-newtype.svg\" alt=\"PyPi\"\u003e\u003c/a\u003e\n\n### CI/CD\n\u003ca href=\"https://codecov.io/github/jymchng/python-newtype-dev?branch=main\"\u003e\u003cimg src=\"https://codecov.io/github/jymchng/python-newtype-dev/coverage.svg?branch=main\" alt=\"Coverage\"\u003e\u003c/a\u003e\n\n### License and Issues\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/jymchng/python-newtype-dev\" alt=\"License\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/issues\"\u003e\u003cimg src=\"https://img.shields.io/github/issues/jymchng/python-newtype-dev\" alt=\"Issues\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/issues?q=is%3Aissue+is%3Aclosed\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-closed/jymchng/python-newtype-dev\" alt=\"Closed Issues\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/issues?q=is%3Aissue+is%3Aopen\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-raw/jymchng/python-newtype-dev\" alt=\"Open Issues\"\u003e\u003c/a\u003e\n\n### Development and Quality\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/network/members\"\u003e\u003cimg src=\"https://img.shields.io/github/forks/jymchng/python-newtype-dev\" alt=\"Forks\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/jymchng/python-newtype-dev\" alt=\"Stars\"\u003e\u003c/a\u003e\n\u003ca href=\"https://pypi.python.org/pypi/python-newtype\"\u003e\u003cimg src=\"https://img.shields.io/pypi/dm/python-newtype\" alt=\"Downloads\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/graphs/contributors\"\u003e\u003cimg src=\"https://img.shields.io/github/contributors/jymchng/python-newtype-dev\" alt=\"Contributors\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/commits/main\"\u003e\u003cimg src=\"https://img.shields.io/github/commit-activity/m/jymchng/python-newtype-dev\" alt=\"Commits\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/commits/main\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/jymchng/python-newtype-dev\" alt=\"Last Commit\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev\"\u003e\u003cimg src=\"https://img.shields.io/github/languages/code-size/jymchng/python-newtype-dev\" alt=\"Code Size\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev\"\u003e\u003cimg src=\"https://img.shields.io/github/repo-size/jymchng/python-newtype-dev\" alt=\"Repo Size\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/watchers\"\u003e\u003cimg src=\"https://img.shields.io/github/watchers/jymchng/python-newtype-dev\" alt=\"Watchers\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev\"\u003e\u003cimg src=\"https://img.shields.io/github/commit-activity/y/jymchng/python-newtype-dev\" alt=\"Activity\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/pulls\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-pr/jymchng/python-newtype-dev\" alt=\"PRs\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/pulls?q=is%3Apr+is%3Aclosed\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-pr-closed/jymchng/python-newtype-dev\" alt=\"Merged PRs\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/jymchng/python-newtype-dev/pulls?q=is%3Apr+is%3Aopen\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-pr/open/jymchng/python-newtype-dev\" alt=\"Open PRs\"\u003e\u003c/a\u003e\n\n\u003c/div\u003e\n\nA powerful Python library for extending existing types with additional functionality while preserving their original behavior, type information and subtype invariances.\n\n## Features\n\n- **Type Wrapping**: Seamlessly wrap existing Python types with new functionality and preservation of subtype invariances when using methods of supertype\n- **Custom Initialization**: Control object initialization with special handling\n- **Attribute Preservation**: Maintains both `__dict__` and `__slots__` attributes\n- **Memory Efficient**: Uses weak references for caching\n- **Debug Support**: Built-in debug printing capabilities for development\n- **Async Support**: Full support for asynchronous methods and operations\n\n## Quick Start\n\n### Installation\n\n```bash\npip install python-newtype\n```\n\n### Basic Usage\n\n```python\nimport pytest\nimport re\nfrom newtype import NewType, newtype_exclude\n\n\nclass EmailStr(NewType(str)):\n    # you can define `__slots__` to save space\n    __slots__ = (\n        '_local_part',\n        '_domain_part',\n    )\n\n    def __init__(self, value: str):\n        super().__init__()\n        if \"@\" not in value:\n            raise TypeError(\"`EmailStr` requires a '@' symbol within\")\n        self._local_part, self._domain_part = value.split(\"@\")\n\n    @newtype_exclude\n    def __str__(self):\n        return f\"\u003cEmail - Local Part: {self.local_part}; Domain Part: {self.domain_part}\u003e\"\n\n    @property\n    def local_part(self):\n        \"\"\"Return the local part of the email address.\"\"\"\n        return self._local_part\n\n    @property\n    def domain_part(self):\n        \"\"\"Return the domain part of the email address.\"\"\"\n        return self._domain_part\n\n    @property\n    def full_email(self):\n        \"\"\"Return the full email address.\"\"\"\n        return str(self)\n\n    @classmethod\n    def from_string(cls, email: str):\n        \"\"\"Create an EmailStr instance from a string.\"\"\"\n        return cls(email)\n\n    @staticmethod\n    def is_valid_email(email: str) -\u003e bool:\n        \"\"\"Check if the provided string is a valid email format.\"\"\"\n        email_regex = r\"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$\"\n        return re.match(email_regex, email) is not None\n\n\ndef test_emailstr_replace():\n    \"\"\"`EmailStr` uses `str.replace(..)` as its own method, returning an instance of `EmailStr`\n    if the resultant `str` instance is a value `EmailStr`.\n    \"\"\"\n    peter_email = EmailStr(\"peter@gmail.com\")\n    smith_email = EmailStr(\"smith@gmail.com\")\n\n    with pytest.raises(Exception):\n        # this raises because `peter_email` is no longer an instance of `EmailStr`\n        peter_email = peter_email.replace(\"peter@gmail.com\", \"petergmail.com\")\n\n    # this works because the entire email can be 'replaced'\n    james_email = smith_email.replace(\"smith@gmail.com\", \"james@gmail.com\")\n\n    # comparison with `str` is built-in\n    assert james_email == \"james@gmail.com\"\n\n    # `james_email` is still an `EmailStr`\n    assert isinstance(james_email, EmailStr)\n\n    # this works because the local part can be 'replaced'\n    jane_email = james_email.replace(\"james\", \"jane\")\n\n    # `jane_email` is still an `EmailStr`\n    assert isinstance(jane_email, EmailStr)\n    assert jane_email == \"jane@gmail.com\"\n\n\ndef test_emailstr_properties_methods():\n    \"\"\"Test the property, class method, and static method of EmailStr.\"\"\"\n    # Test property\n    email = EmailStr(\"test@example.com\")\n    # `property` is not coerced to `EmailStr`\n    assert email.full_email == \"\u003cEmail - Local Part: test; Domain Part: example.com\u003e\"\n    assert isinstance(email.full_email, str)\n    # `property` is not coerced to `EmailStr`\n    assert not isinstance(email.full_email, EmailStr)\n    assert email.local_part == \"test\"\n    assert email.domain_part == \"example.com\"\n\n    # Test class method\n    email_from_string = EmailStr.from_string(\"classmethod@example.com\")\n    # `property` is not coerced to `EmailStr`\n    assert (\n        email_from_string.full_email\n        == \"\u003cEmail - Local Part: classmethod; Domain Part: example.com\u003e\"\n    )\n    assert email_from_string.local_part == \"classmethod\"\n    assert email_from_string.domain_part == \"example.com\"\n\n    # Test static method\n    assert EmailStr.is_valid_email(\"valid.email@example.com\") is True\n    assert EmailStr.is_valid_email(\"invalid-email.com\") is False\n\n\ndef test_email_str__slots__():\n    email = EmailStr(\"test@example.com\")\n\n    with pytest.raises(AttributeError):\n        email.hi = \"bye\"\n        assert email.hi == \"bye\"\n```\n\n## Documentation\n\nFor detailed documentation, visit [py-nt.asyncmove.com](https://py-nt.asyncmove.com/).\n\n### Key Topics:\n- [Installation Guide](https://py-nt.asyncmove.com/getting-started/installation/)\n- [Quick Start Guide](https://py-nt.asyncmove.com/getting-started/quickstart/)\n- [User Guide](https://py-nt.asyncmove.com/user-guide/basic-usage/)\n- [API Reference](https://py-nt.asyncmove.com/api/newtype/)\n\n## Development\n\n### Prerequisites\n\n- Python 3.8 or higher\n- C compiler (for building extensions)\n- Development packages:\n  ```bash\n  make install-dev-deps\n  ```\n\n### Building from Source\n\n```bash\ngit clone https://github.com/jymchng/python-newtype-dev.git\ncd python-newtype-dev\nmake build\n```\n\n### Install from Source\n\n```bash\ngit clone https://github.com/jymchng/python-newtype-dev.git\ncd python-newtype-dev\nmake install\n```\n\n### Running Tests\n\n```bash\n# Run all tests\nmake test\n\n# Run with debug output\nmake test-debug\n\n# Run specific test suite\nmake test-custom\n```\n\n## Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](https://py-nt.asyncmove.com/development/contributing/) for details.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\nSpecial thanks to all contributors who have helped shape this project.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjymchng%2Fpython-newtype-dev","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjymchng%2Fpython-newtype-dev","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjymchng%2Fpython-newtype-dev/lists"}