{"id":16943839,"url":"https://github.com/brocksam/pyproprop","last_synced_at":"2025-06-11T08:08:05.261Z","repository":{"id":47093298,"uuid":"272819140","full_name":"brocksam/pyproprop","owner":"brocksam","description":"Write classes with lots of similar simple defensive properties without the boilerplate","archived":false,"fork":false,"pushed_at":"2021-09-14T14:56:10.000Z","size":328,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-11T08:07:58.819Z","etag":null,"topics":["bounds-checking","properties","type-casting","type-checking"],"latest_commit_sha":null,"homepage":"","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/brocksam.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-16T21:50:01.000Z","updated_at":"2021-09-14T14:56:13.000Z","dependencies_parsed_at":"2022-09-16T23:41:47.093Z","dependency_job_id":null,"html_url":"https://github.com/brocksam/pyproprop","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brocksam%2Fpyproprop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brocksam%2Fpyproprop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brocksam%2Fpyproprop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brocksam%2Fpyproprop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brocksam","download_url":"https://codeload.github.com/brocksam/pyproprop/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brocksam%2Fpyproprop/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259227951,"owners_count":22824903,"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","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":["bounds-checking","properties","type-casting","type-checking"],"created_at":"2024-10-13T21:15:25.398Z","updated_at":"2025-06-11T08:08:05.236Z","avatar_url":"https://github.com/brocksam.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"*********\nPyproprop\n*********\n\nPackage for aiding writing classes with lots of similar simple properties without the boilerplate.\n\nStatus\n======\n\n.. list-table::\n   :widths: 50 50 50 50\n\n   * - **Latest Release**\n     - .. image:: https://img.shields.io/pypi/v/pyproprop?color=brightgreen\u0026label=version\n            :alt: PyPI\n            :target: https://pypi.org/project/pyproprop/\n     - **Docs**\n     - .. image:: https://readthedocs.org/projects/pyproprop/badge/?version=latest\n            :target: https://pyproprop.readthedocs.io/en/latest/?badge=latest\n            :alt: Documentation Status\n   * - **PyPI**\n     - .. image:: https://img.shields.io/pypi/dm/pyproprop?color=brightgreen\u0026label=downloads\u0026logo=pypi\n            :alt: PyPI - Downloads\n            :target: https://pypi.org/project/pyproprop/\n     - **Anaconda**\n     - .. image:: https://img.shields.io/conda/dn/conda-forge/pyproprop?color=brightgreen\u0026label=downloads\u0026logo=conda-forge\n            :alt: Conda\n            :target: https://anaconda.org/conda-forge/pyproprop\n   * - **Coverage**\n     - .. image:: https://img.shields.io/codecov/c/github/brocksam/pyproprop?color=brightgreen\u0026logo=codecov\n            :alt: Codecov\n     - **License**\n     - .. image:: https://img.shields.io/badge/license-MIT-brightgreen.svg\n           :target: https://github.com/brocksam/pyproprop/blob/master/LICENSE\n\n\n\nWhat is Pyproprop?\n==================\n\nDo you often find yourself writing classes with properties such as:\n\n.. code-block:: python\n\n    from some_other_module import DefaultObject, some_type\n\n    class ExampleClass:\n\n        def __init__(self,\n                     type_checked_value,\n                     bounded_numeric_value,\n                     specific_length_sequence_value,\n                     obj_with_method_applied_value,\n                     ):\n            self.type_check_attr = type_checked_value\n            self.bounded_numeric_attr = bounded_numeric_value\n            self.specific_length_sequence_attr = specific_length_sequence_value\n            self.obj_with_method_applied_attr = obj_with_method_applied_value\n            self.instantiate_default_if_none_attr = None\n\n        @property\n        def type_checked_attr(self):\n            return self._type_checked_attr\n\n        @type_checked_attr.setter\n        def type_checked_attr(self, val):\n            if not isinstance(val, some_type):\n                msg = \"`type_checked_attr` must be of `some_type`\"\n                raise TypeError(msg)\n            self._type_checked_attr = val\n\n        @property\n        def bounded_numeric_attr(self):\n            return self._bounded_numeric_attr\n\n        @bounded_numeric_attr.setter\n        def bounded_numeric_attr(self, val):\n            val = float(val)\n            lower_bound = -1.0\n            upper_bound = 2.5\n            if val \u003c lower_bound:\n                msg = f\"`bounded_numeric_attr` must be greater than {lower_bound}\"\n                raise ValueError(msg)\n            if val \u003e= upper_bound:\n                msg = (f\"`bounded_numeric_attr` must be less than or equal to \"\n                       f\"{upper_bound}.\")\n                raise ValueError(msg)\n            self._type_checked_attr = val\n\n        @property\n        def specific_length_sequence_attr(self):\n            return self._specific_length_sequence_attr\n\n        @specific_length_sequence_attr.setter\n        def specific_length_sequence_attr(self, val):\n            if len(val) != 2:\n                msg = \"`specific_length_sequence` must be an iterable of length 2.\"\n                raise ValueError(msg)\n            self._specific_length_sequence_attr = val\n\n        @property\n        def obj_with_method_applied_value(self):\n            return self._obj_with_method_applied_value\n\n        @obj_with_method_applied_value.setter\n        def obj_with_method_applied_value(self, val):\n            val = str(val)\n            self._obj_with_method_applied_value = val.title()\n\n        @property\n        def instantiate_default_if_none_attr(self):\n            return self._instantiate_default_if_none_attr\n\n        @instantiate_default_if_none_attr.setter\n        def instantiate_default_if_none_attr(self, val):\n            if val is None:\n                val = DefaultObject()\n            self._instantiate_default_if_none_attr = val\n\nWith *Pyproprop* all of this boilerplate can be removed and instead the exact same class can be rewritten as:\n\n.. code-block:: python\n\n    from pyproprop import processed_property\n    from some_other_module import DefaultObject, some_type\n\n    class ExampleClass:\n\n        type_checked_attr = processed_property(\n            \"type_checked_attr\",\n            description=\"property with enforced type of `some_type`\",\n            type=some_type,\n        )\n        bounded_numeric_attr = processed_property(\n            \"bounded_numeric_attr\",\n            description=\"numerical attribute with upper and lower bounds\"\n            type=float,\n            cast=True,\n            min=-1.0,\n            max=2.5,\n        )\n        specific_length_sequence_attr = processed_property(\n            \"specific_length_sequence_attr\",\n            description=\"sequence of length exactly 2\",\n            len=2,\n        )\n        obj_with_method_applied_attr = processed_property(\n            \"obj_with_method_applied_attr\",\n            description=\"sting formatted to use title case\"\n            type=str,\n            cast=True,\n            method=\"title\",\n        )\n        instantiate_default_if_none_attr = processed_property(\n            \"instantiate_default_if_none_attr\",\n            default=DefaultObject,\n        )\n\n        def __init__(self,\n                     type_checked_value,\n                     bounded_numeric_value,\n                     specific_length_sequence_value,\n                     obj_with_method_applied_value,\n                     ):\n            self.type_check_attr = type_checked_value\n            self.bounded_numeric_attr = bounded_numeric_value\n            self.specific_length_sequence_attr = specific_length_sequence_value\n            self.obj_with_method_applied_attr = obj_with_method_applied_value\n            self.instantiate_default_if_none_attr = None\n\nInstallation\n============\n\nThe easiest way to install *Pyproprop* is using the `Anaconda Python distribution \u003chttps://www.anaconda.com/what-is-anaconda/\u003e`_ and its included *Conda* package management system. To install *Pyproprop* and its required dependencies, enter the following command at a command prompt:\n\n.. code-block:: bash\n\n    conda install pyproprop\n\nTo install using pip, enter the following command at a command prompt:\n\n.. code-block:: bash\n\n    pip install pyproprop\n\nFor more information, refer to the `installation documentation \u003chttps://pyproprop.readthedocs.io/en/latest/user/installation.html\u003e`_.\n\nContribute\n==========\n\n- Issue Tracker: https://github.com/brocksam/pyproprop/issues\n- Source Code: https://github.com/brocksam/pyproprop\n\nLicense\n=======\n\nThis project is licensed under the terms of the `MIT license \u003cLICENSE\u003e`_.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrocksam%2Fpyproprop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrocksam%2Fpyproprop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrocksam%2Fpyproprop/lists"}