{"id":17114710,"url":"https://github.com/sundarnagarajan/pyprotect","last_synced_at":"2025-04-13T04:08:17.915Z","repository":{"id":55776249,"uuid":"320788052","full_name":"sundarnagarajan/pyprotect","owner":"sundarnagarajan","description":"Protect class attributes in any python object instance","archived":false,"fork":false,"pushed_at":"2023-01-28T05:55:05.000Z","size":11424,"stargazers_count":4,"open_issues_count":7,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-13T04:08:13.771Z","etag":null,"topics":["cython","immutable","mutability","pip3","private-attribute","private-variables","pypy","pypy3","python","python2","python3","readonly-attribue","venv","virtualenv","visibility"],"latest_commit_sha":null,"homepage":"","language":"Cython","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sundarnagarajan.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}},"created_at":"2020-12-12T08:56:02.000Z","updated_at":"2024-01-12T18:16:53.000Z","dependencies_parsed_at":"2023-02-15T14:31:02.541Z","dependency_job_id":null,"html_url":"https://github.com/sundarnagarajan/pyprotect","commit_stats":null,"previous_names":["sundarnagarajan/python_protected_class"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sundarnagarajan%2Fpyprotect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sundarnagarajan%2Fpyprotect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sundarnagarajan%2Fpyprotect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sundarnagarajan%2Fpyprotect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sundarnagarajan","download_url":"https://codeload.github.com/sundarnagarajan/pyprotect/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248661704,"owners_count":21141450,"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":["cython","immutable","mutability","pip3","private-attribute","private-variables","pypy","pypy3","python","python2","python3","readonly-attribue","venv","virtualenv","visibility"],"created_at":"2024-10-14T17:19:55.227Z","updated_at":"2025-04-13T04:08:17.884Z","avatar_url":"https://github.com/sundarnagarajan.png","language":"Cython","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Restrict visibility or mutability of Python object attributes\npyprotect is a python module that provides API to restrict visibility or mutability of selected Python object attributes in a robust manner.\n\nThe key functions in the pyprotect module API - __private()__ and __protect()__ wrap the python object (like a _Proxy_) to restrict visibility or mutability of selected attributes of the wrapped object, while allowing the __wrapping__ object to behave virtually identical to the __wrapped__ object.\n\n## Features\n- Can wrap virtually any Python object - instances, classes (types), modules, methods, classmethods, instancemethods, staticmethods, partials, lambdas.\n- Tested on Python 2.7 and Python 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11\n- Tested on the following distributions with the latest versions of python2, python3, pypy3, pypy shipped by the respective distributions:\n    - Ubuntu Jammy 22.04\n    - Arch linux (20220101)\n    - Fedora 37\n    - Alpine Linux 3.15 (Alpine 3.16 does not have python2-dev)\n- Has extensive unit (functional) tests - in [_tests_](https://github.com/sundarnagarajan/python_protected_class/tree/main/tests) directory.\n\n## Table of Contents\n\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n* [Quick start](#quick-start)\n* [Classes](#classes)\n* [Features of key classes](#features-of-key-classes)\n    * [Wrapped](#wrapped)\n    * [Frozen](#frozen)\n    * [Private](#private)\n    * [FrozenPrivate](#frozenprivate)\n    * [Protected](#protected)\n    * [FrozenProtected](#frozenprotected)\n* [API](#api)\n    * [Wrapping API](#wrapping-api)\n        * [freeze](#freeze)\n        * [private](#private-1)\n        * [protect](#protect)\n        * [wrap](#wrap)\n    * [Checking types of wrapped objects](#checking-types-of-wrapped-objects)\n        * [isfrozen](#isfrozen)\n        * [isimmutable](#isimmutable)\n        * [isprivate](#isprivate)\n        * [isprotected](#isprotected)\n    * [Checking properties of objects inside wrapped objects](#checking-properties-of-objects-inside-wrapped-objects)\n        * [contains](#contains)\n        * [help_protected](#help_protected)\n        * [id_protected](#id_protected)\n        * [isinstance_protected](#isinstance_protected)\n        * [isreadonly](#isreadonly)\n        * [instance_of_protected](#instance_of_protected)\n        * [isvisible](#isvisible)\n        * [same_class_protected](#same_class_protected)\n        * [subclass_of_protected](#subclass_of_protected)\n    * [pyprotect module metadata](#pyprotect-module-metadata)\n        * [immutable_builtin_attributes](#immutable_builtin_attributes)\n        * [always_delegated_attributes](#always_delegated_attributes)\n        * [attribute_protected](#attribute_protected)\n        * [hidden_pickle_attributes](#hidden_pickle_attributes)\n        * [never_writeable](#never_writeable)\n        * [never_writeable_private](#never_writeable_private)\n* [Calling wrap operations multiple times](#calling-wrap-operations-multiple-times)\n* [Python rules for attributes of type 'property':](#python-rules-for-attributes-of-type-property)\n* [What kind of python objects can be wrapped?](#what-kind-of-python-objects-can-be-wrapped)\n* [Work in progress](#work-in-progress)\n* [Changelog](#changelog)\n    * [Jan-20-2022](#jan-20-2022)\n    * [Jan-15-2022](#jan-15-2022)\n    * [Dec-08-2022](#dec-08-2022)\n\n\u003c!-- vim-markdown-toc --\u003e\n\n## Quick start\n```python\n\nfreeze(o: object) -\u003e Frozen:\n```\n- If _o_ is immutable (e.g. int , string), returns _o_ UNCHANGED\n- If _o_ is Wrapped, returns _o_ UNCHANGED if object WRAPPPED INSIDE _o_ is immutable, returns Frozen otherwise\n- If _o_ is Frozen, returns _o_ UNCHANGED\n- If _o_ is FrozenPrivate, FrozenProtected or FrozenPrivacyDict, returns _o_ UNCHANGED\n- If _o_ is Private, returns FrozenPrivate\n- If _o_ is Protected, returns FrozenProtected\n- Otherwise, returns Frozen\n    \nObject returned prevents modification of ANY attribute\n\n```python\nprivate(o: object, frozen: bool = False) -\u003e object:\n```\n - If _frozen_ is False:\n      - If _o_ is an instance of Private, returns _o_ UNCHANGED\n     - If 'o' is an instance of Protected, returns _o_ UNCHANGED\n- If _frozen_ is True:\n     - If _o_ is an instance of Private, returns _freeze(o)_ (FrozenPrivate)\n     - If _o_ is an instance of Protected, returns _freeze(o)_ (FrozenProtected)\n     - Otherwise:\n          If _frozen_ is True, returns FrozenPrivate; returns Private otherwise\n\n```python\nprotect(\n    o: object frozen: bool = False,\n    dynamic: bool = True,\n    hide_private: bool = False,\n    ro_data: bool = False,\n    ro_method: bool = True,\n    ro: List[str] = [],\n    rw: List[str] = [],\n    hide: List[str] = []\n) -\u003e object:\n# o--\u003eobject to be wrapped\n```\nReturns--\u003eInstance of __FrozenProtected__ if _frozen_; Instance of __Protected__ otherwise\n\nIf _protect()_ is called on an object 'o' that is an instance of Protected, _protect()_ will merge the _protect()_ rules, enforcing the most restrictive combination among the two sets of protect() options:\n- _hide_ and _hide_private_ are OR-ed\n- _ro_method_, _ro_data_ and _ro_ are OR-ed\n- _rw_ is AND-ed, but _rw_ of second protect overrides _ro*_ of __second__ protect but __not__ the __first__ protect.\n    \nIn short, by calling protect() a second time (or multiple times):\n- Additoinal attributes can be hidden\n- Additional attributes can be made read-only\n- No previously hidden attribute will become visible\n- No previously read-only attribute will become mutable\n\n\n__Options: protect method arguments__\n| Option       | Type        | Default | Description                                                                            | Overrides                  |\n|--------------|-------------|---------|----------------------------------------------------------------------------------------|----------------------------|\n| frozen       | bool        | False   | If True, no attributes can be changed, added or deleted                                |                            |\n| hide_private | bool        | False   | If True, private vars of the form ```_var``` will be hidden                            |                            |\n| ro_data      | bool        | False   | Data (non-method) attributes will be immutable\u003cbr\u003eCan override selectively with __rw__ |                            |\n| ro_method    | bool        | True    | Method (callable) attributes will be immutable\u003cbr\u003eCan override selectively with __rw__ |                            |\n| ro           | list of str | [ ]      | Attributes that will be immutable\u003cbr\u003eCan override selectively with __rw__              |                            |\n| rw           | list of str | [ ]      | Attributes that will be mutable                                                        | ro_data\u003cbr\u003ero_method\u003cbr\u003ero |\n| hide         | list of str | [ ]   |                                                                                        |                            |\n\n__Visibility and mutability of attributes with protect() method__\n\n| Option       | Attribute Type     | Restricts Visibility | Restricts Mutability |\n|--------------|--------------------|-----------------------|----------------------|\n| frozen       | Any                | NO                    | YES                  |\n| hide_private | Private attributes | YES                   | YES (Indirect)       |\n| ro_data      | Data attributes    | NO                    | YES                  |\n| ro_method    | Method attributes  | NO                    | YES                  |\n| ro           | ANY                | NO                    | YES                  |\n| rw           | ANY                | NO                    | YES                  |\n| hide         | ANY                | YES                   | YES (Indirect)       |\n\n## Classes\n\n![class diagram](docs/classdiagram.svg \"class diagram\")\n\n## Features of key classes\n### Wrapped\n- Visibility: No additional restrictions\n- Mutability: No additional restrictions\n### Frozen\n- Visibility: Does not __additionally__ restrict visibility of any attributes in __wrapped__ object accessed through __wrapping__ object\n- Mutability: Prevents modification of ANY attribute\n### Private\n- Visibility:\n    - Cannot access traditionally 'private' mangled python attributes\n    - Cannot modify traditionally private attributes (form '_var_')\n    - Attributes not part of dir(wrapped_object) are not visible\n- Mutability:\n    - The following attributes of wrapped object are NEVER writeable:\n        ```__class__```, ```__dict__```, ```__delattr__```, ```__setattr__```, ```__slots__```, ```__getattribute__```\n    - Traditional (mangled) Python private vars are ALWAYS hidden\n    - Private vars (form \\_var) will be read-only\n    - Attributes cannot be added or removed\n    - Attributes that are properties are ALWAYS visible AND WRITABLE (except if '_frozen_' is used)\n        - Properties indicate an intention of class author to expose them\n        - Whether they are actually writable depends on whether class author implemented property.setter\n### FrozenPrivate\n- Visibility: Same as Private\n- Mutability: Prevents modification of ANY attribute\n### Protected\n- Features of Private PLUS allows __further restriction__ of:\n    - Which attributes are VISIBLE\n    - Which attributes are WRITEABLE\n- Default settings:\n    - Features of Private - see above\n    - dynamic == True\n        Attribute additions, deletions, type changes automatically visible\n    - ro_method == True: Method attributes will be read-only\n    - All other non-private data attributes are read-write\n### FrozenProtected\n- Features of Protected PLUS prevents modification of ANY attribute\n\n## API\n### Wrapping API\n#### freeze\n```python\n\nfreeze(o: object) -\u003e Frozen:\n```\n- If _o_ is immutable (e.g. int , string), returns _o_ UNCHANGED\n- If _o_ is Wrapped, returns _o_ UNCHANGED if object WRAPPPED INSIDE _o_ is immutable, returns Frozen otherwise\n- If _o_ is Frozen, returns _o_ UNCHANGED\n- If _o_ is FrozenPrivate, FrozenProtected or FrozenPrivacyDict, returns _o_ UNCHANGED\n- If _o_ is Private, returns FrozenPrivate\n- If _o_ is Protected, returns FrozenProtected\n- Otherwise, returns Frozen\n    \nObject returned prevents modification of ANY attribute\n\n#### private\n```python\nprivate(o: object, frozen: bool = False) -\u003e object:\n```\n - If _frozen_ is False:\n      - If _o_ is an instance of Private, returns _o_ UNCHANGED\n     - If 'o' is an instance of Protected, returns _o_ UNCHANGED\n- If _frozen_ is True:\n     - If _o_ is an instance of Private, returns _freeze(o)_ (FrozenPrivate)\n     - If _o_ is an instance of Protected, returns _freeze(o)_ (FrozenProtected)\n     - Otherwise:\n          If _frozen_ is True, returns FrozenPrivate; returns Private otherwise\n\n#### protect\n```python\nprotect(\n    o: object frozen: bool = False,\n    dynamic: bool = True,\n    hide_private: bool = False,\n    ro_data: bool = False,\n    ro_method: bool = True,\n    ro: List[str] = [],\n    rw: List[str] = [],\n    hide: List[str] = []\n) -\u003e object:\n# o--\u003eobject to be wrapped\n```\nReturns--\u003eInstance of __FrozenProtected__ if _frozen_; Instance of __Protected__ otherwise\n\nIf _protect()_ is called on an object 'o' that is an instance of Protected, _protect()_ will merge the _protect()_ rules, enforcing the most restrictive combination among the two sets of protect() options:\n- _hide_ and _hide_private_ are OR-ed\n- _ro_method_, _ro_data_ and _ro_ are OR-ed\n- _rw_ is AND-ed, but _rw_ of second protect overrides _ro*_ of __second__ protect but __not__ the __first__ protect.\n    \nIn short, by calling protect() a second time (or multiple times):\n- Additoinal attributes can be hidden\n- Additional attributes can be made read-only\n- No previously hidden attribute will become visible\n- No previously read-only attribute will become mutable\n\n__Options: protect method arguments__\n| Option       | Type        | Default | Description                                                                            | Overrides                  |\n|--------------|-------------|---------|----------------------------------------------------------------------------------------|----------------------------|\n| frozen       | bool        | False   | If True, no attributes can be changed, added or deleted                                |                            |\n| hide_private | bool        | False   | If True, private vars of the form ```_var``` will be hidden                            |                            |\n| ro_data      | bool        | False   | Data (non-method) attributes will be immutable\u003cbr\u003eCan override selectively with __rw__ |                            |\n| ro_method    | bool        | True    | Method (callable) attributes will be immutable\u003cbr\u003eCan override selectively with __rw__ |                            |\n| ro           | list of str | [ ]      | Attributes that will be immutable\u003cbr\u003eCan override selectively with __rw__              |                            |\n| rw           | list of str | [ ]      | Attributes that will be mutable                                                        | ro_data\u003cbr\u003ero_method\u003cbr\u003ero |\n| hide         | list of str | [ ]   |                                                                                        |                            |\n\n__Visibility and mutability of attributes with protect() method__\n\n| Option       | Attribute Type     | Restricts Visibility | Restricts Mutability |\n|--------------|--------------------|-----------------------|----------------------|\n| frozen       | Any                | NO                    | YES                  |\n| hide_private | Private attributes | YES                   | YES (Indirect)       |\n| ro_data      | Data attributes    | NO                    | YES                  |\n| ro_method    | Method attributes  | NO                    | YES                  |\n| ro           | ANY                | NO                    | YES                  |\n| rw           | ANY                | NO                    | YES                  |\n| hide         | ANY                | YES                   | YES (Indirect)       |\n\n#### wrap\n```python\nwrap(o: object) -\u003e Wrapped:\n```\n- Should behave just like the wrapped object, except following attributes cannot be modified:\n    ```__getattribute__```, ```__delattr__```, ```__setattr__```, ```__slots__```\n- Explicitly does NOT support pickling, and will raise _pickle.PicklingError_\n- Does NOT protect CLASS (or ```__class__```) of wrapped object from modification\n- Does NOT protect ```__dict__``` or ```__slots__```\n    \nUseful for testing if wrapping is failing for a particular type of object\n\n###  Checking types of wrapped objects\n#### isfrozen\n```python\nisfrozen(x: object) -\u003e bool\n```\n_x_ was created using _freeze()_ or _private(o, frozen=True)_ or _protect(o, frozen=True)_\n\n#### isimmutable\n```python\nisimmutable(x: object) -\u003e bool\n```\n_x_ is known to be immutable\n\n#### isprivate\n```python\nisprivate(x: object) -\u003e bool\n```\n_x_ was created using _private()_\n\n#### isprotected\n```python\nisprotected(x: object) -\u003e bool\n```\n_x_ was created using _protect()_\n\n### Checking properties of objects inside wrapped objects\n#### contains\n```python\ncontains(w: object, o: object) -\u003e bool\n```\nIf _w_ is a wrapped object (_iswrapped(w)_ is True), returns whether _w_ wraps _o_\nOtherwise unconditionally returns False\n\n#### help_protected\n```python\nhelp_protected(x: object) -\u003e None\n```\nIf _x_ wraps _o_, executes _help(o)_\nOtherwise executes h_elp(x)_\n\n#### id_protected\n```python\nid_protected(x: object) -\u003e int\n```\nif _x_ is a wrapped object (_iswrapped(x)_ is True) and _x_ wraps _o_, returns _id(o)_\nOtherwise returns _id(x)_\n\n#### isinstance_protected\n```python\nisinstance_protected(x: object, t: type) -\u003e bool\n```\nIf _x_ is a wrapped object (_iswrapped(x)_ is True) and _x_ wraps _o_, returns _isinstance(o, t)_\nOtherwise returns _isinstance(x, t)_\n\n#### isreadonly\n```python\nisreadonly(x: object, a: str) -\u003e bool\n```\nIf _x_ is a wrapped object - with _iswrapped(x)_ == True - and _x_ wraps _o_, _isreadonly(x, a)_ returns whether rules of __wrapper__ make attribute _a_ read-only when accessed through _x_\nThis represents __rule__ of wrapped object - does not guarantee that_o_ has attribute_a_ or that setting attribute _a_ in object _o_ will not raise any exception\nIf _x_ is __not__ a wrapped object (_iswrapped(x)_ is False) , unconditionally returns False\n\n#### instance_of_protected\n```python\ninstance_of_protected(x: object, o: object) -\u003e bool\n```\nIf _x_ is a wrapped object - with _iswrapped(x)_ == True - and _x_ wraps _o_, _instance_of_protected(x, o)_ returns True if and only if _isinstance(x, type(o))_\nIf _x_ is not a wrapped object - _iswrapped(x)_ == False - _instance_of_protected(x, o)_ returns _isinstance(x, o)_\n\n#### isvisible\n```python\nisvisible(x: object, a: str) -\u003e bool\n```\nReturns False if and only if _iswrapped(x)_ is True AND _x_ makes attribute _a_ invisible if present in wrapped object\n\u003cbr\u003e\nThis represents __rule__ of wrapped object - does not guarantee that __wrapped object__ has attribute _a_ or that accessing attribute _a_ in object _x_ will not raise any exception\n\u003cbr\u003e        \nIf _x_ is not a wrapped object, unconditionally returns False\n\n#### same_class_protected\n```python\nsame_class_protected(c: type, w: object) -\u003e bool\n```\nIf _iswrapped(w)_ and _w_ wraps _o_: Returns _(c is type(o))_\n\u003cbr\u003e\nOtherwise: returns _(c is type(w))_\n\n#### subclass_of_protected\n```python\nsubclass_of_protected(x: object, w: object) -\u003e bool\n```\nIf _iswrapped(w)_ and _w_ wraps _o_: Returns _issubclass(x, type(o))_\n\u003cbr\u003e\nOtherwise: returns _issubclass(x, w)_\n\n### pyprotect module metadata\n#### immutable_builtin_attributes\n```python\nimmutable_builtin_attributes() -\u003e Set[str]\n```\nReturns--\u003eset of str: attributes in builtins that are immutable\nUsed in unit tests\n\n#### always_delegated_attributes\n```python\nalways_delegated_attributes() -\u003e set(str)\n```\nAttributes that are always delegated to wrapped object\n\n#### attribute_protected\n```python\nattribute_protected() -\u003e str\n```\nName of special attribute in Wrapped objects\n\n#### hidden_pickle_attributes\n```python\nhidden_pickle_attributes() -\u003e set(str)\n```\nAttributes that are never visible in object 'o' if iswrapped(o) - to disallow pickling\n\n#### never_writeable\n```python\nnever_writeable() -\u003e set(str)\n```\nAttributes that are never writeable in object _o_ if _iswrapped(o)_\n\n#### never_writeable_private\n```python\nnever_writeable_private() -\u003e set(str)\n```\nAttributes that are never writeable in object _o_ if _isprivate(o)_\n\n## Calling wrap operations multiple times\n\nIn the table below:\n- The left-most column shows starting state.\n- The top row shows operation applied to the starting state.\n- The intersecting cell shows the result.\n- _UNCH_ represents operation returning the starting state unchanged\n\n| Operation  🡆\u003cbr\u003eOn type 🡇 | wrap       | freeze          | private       | private\u003cbr\u003e+ frozen | protect                | protect\u003cbr\u003e+ frozen    |\n|---------------------------|------------|-----------------|---------------|---------------------|------------------------|------------------------|\n| Ordinary object\u003cbr\u003e_iswrapped(x)_ is False                   | Wrapped       | Frozen\u003cbr\u003e(2)       | Private       | FrozenPrivate       | Protected              | FrozenProtected        |\n| Wrapped                   | UNCH       | Frozen\u003cbr\u003e(2)       | Private       | FrozenPrivate       | Protected              | FrozenProtected        |\n| Frozen                    | Wrapped\u003cbr\u003e(2) | UNCH\u003cbr\u003e(2)     | FrozenPrivate | FrozenPrivate       | FrozenProtected        | FrozenProtected        |\n| Private                   | UNCH       | FrozenPrivate   | UNCH          | FrozenPrivate       | Protected              | FrozenProtected        |\n| FrozenPrivate             | UNCH       | UNCH            | UNCH          | UNCH                | FrozenProtected        | FrozenProtected        |\n| Protected                 | UNCH       | FrozenProtected | UNCH          | FrozenProtected     | Protected\u003cbr\u003e(1)           | FrozenProtected\u003cbr\u003e(1)     |\n| FrozenProtected           | UNCH       | UNCH            | UNCH          | UNCH                | FrozenProtected\u003cbr\u003e(1) | FrozenProtected\u003cbr\u003e(1) |\n\n1. _protect()_ applied twice will merge the _protect()_ rules, enforcing the most restrictive combination among the two sets of protect() options:\n- _hide_ and _hide_private_ are OR-ed\n- _ro_method_, _ro_data_ and _ro_ are OR-ed\n- _rw_ is AND-ed, but _rw_ of second protect overrides _ro*_ of __second__ protect but __not__ the __first__ protect.\n    \nIn short, by calling protect() a second time (or multiple times):\n    - Additoinal attributes can be hidden\n    - Additional attributes can be made read-only\nbut:\n    - No previously hidden attribute will become visible\n    - No previously read-only attribute will become mutable\n\n2. If _x_ is an immutable object (e.g. int, str ...) having _isimmutable(x) \\=\\= True_, _freeze(x)_ returns _x_ and _iswrapped(freeze(x))_ will be False.\n    \nFor all other objects _x_, having _isimmutable(x) \\=\\= False_, _freeze(x)_ will return a Frozen object having _iswrapped(freeze(x)) == True_\n    \nFor all other wrapped objects _w_, created with _private(x)_ or _protect(x)_, _freeze(w)_ will always return a Wrapped object with _iswrapped(w) == True_\n\n## Python rules for attributes of type 'property':\n- Properties are defined in the CLASS, and cannot be changed in the object INSTANCE\n- Properties cannot be DELETED\n- Properties cannot be WRITTEN to unless property has a 'setter' method defined in the CLASS\n- These rules are implemented by the python language (interpreter) and Protected class does not enforce or check\n\n## What kind of python objects can be wrapped?\nPretty much anything. pyprotect only mediates attribute access using ```object.__getattribute__```, ```object.__setattr__``` and ```object.__delatr__```. If these methods work on your object, your object can be wrapped\n\n## Work in progress\n- Uploading to pypi.org\n- [Test cases required](https://github.com/sundarnagarajan/python_protected_class/issues?q=is%3Aopen+is%3Aissue+label%3ATests)\n\n## Changelog\n### Jan-20-2022\n- Project name on github changed to ```pyprotect``` to match the name of the module. This has been long-pending. The [old github link](https://github.com/sundarnagarajan/python_protected_class) redirects to the new project name. \n### Jan-15-2022\n- Started signing commits with my GPG key and displaying 'verified' for signed commits\n### Dec-08-2022\nA number of parameters to protect() have been discontinued. See list and reasons below, as well as how to achieve the same effect without thos parameters (sometimes, it takes more work). Most of them would be realistically useful very rarely, and / or do not align with what I call 'idiomatic python'.\n\n**hide_all, hide_method, hide_dunder**\nSo-called 'special methods' in Python serve an important functional roles - especially in emulating containers (tuples, lists, sets, dicts), emulating numeric types supporting arithmetic operators, numeric comparisons etc. If such specific 'dunder methods' were hidden, it would definitely affect the behavior of the wrapped object. ```hide_dunder``` would hide all such special methods. ```hide_method``` would in addition hide all methods in the objest. ```hide_all``` would hide all object attributes, making the object virtually useless, and the option useful in testing (if at all).\n\n**hide_data**\nIn most cases, hiding all non-method data attributes will make the object less useful / cripple the expected usage of the object. Specific use-cases can be achieved using the 'hide' parameter.\n\n**ro_dunder**\nSeems like it can be replaced by using ro_method' Mostly, in 'idiomatic python', methods of a class / instance are not mutated from outside the class / instance. This expected 'idiomatic python' behavior can be achieved with 'ro_method'.\n\n**ro_all**\nIs unnecessary, since 'frozen' can be used instead.\n\n**add**\nIn my opinion, 'add' does not align with 'idiomatic python'. While Python allows users of a class / instance adding attributes to the class / instance, that is not the expected style. Based on this, I have decided to promote that 'idiomatic style', and prevent adding / deleting any attributes in a Private or Protected object.\n\n**show**\nIt is unnecessary, since all attributes are visible by default in Python. Only 'hide' or 'hide_private' will hide any attributes.\n\nThis leaves the following (incidentally also reducing testing load):\n\n\t- Visibility:\n\t\t- hide_private\n\t\t- hide\n\t- Mutability:\n\t\t- ro_data\n\t\t- ro_method\n\t\t- ro\n\t\t- rw\n\t\t- frozen\n\t- Behavior:\n\t\t- dynamic\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsundarnagarajan%2Fpyprotect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsundarnagarajan%2Fpyprotect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsundarnagarajan%2Fpyprotect/lists"}