Git Product home page Git Product logo

pyprotect's Introduction

Restrict visibility or mutability of Python object attributes

pyprotect is a python module that provides API to restrict visibility or mutability of selected Python object attributes in a robust manner.

The 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.

Features

  • Can wrap virtually any Python object - instances, classes (types), modules, methods, classmethods, instancemethods, staticmethods, partials, lambdas.
  • Tested on Python 2.7 and Python 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11
  • Tested on the following distributions with the latest versions of python2, python3, pypy3, pypy shipped by the respective distributions:
    • Ubuntu Jammy 22.04
    • Arch linux (20220101)
    • Fedora 37
    • Alpine Linux 3.15 (Alpine 3.16 does not have python2-dev)
  • Has extensive unit (functional) tests - in tests directory.

Table of Contents

Quick start

freeze(o: object) -> Frozen:
  • If o is immutable (e.g. int , string), returns o UNCHANGED
  • If o is Wrapped, returns o UNCHANGED if object WRAPPPED INSIDE o is immutable, returns Frozen otherwise
  • If o is Frozen, returns o UNCHANGED
  • If o is FrozenPrivate, FrozenProtected or FrozenPrivacyDict, returns o UNCHANGED
  • If o is Private, returns FrozenPrivate
  • If o is Protected, returns FrozenProtected
  • Otherwise, returns Frozen

Object returned prevents modification of ANY attribute

private(o: object, frozen: bool = False) -> object:
  • If frozen is False:
    • If o is an instance of Private, returns o UNCHANGED
    • If 'o' is an instance of Protected, returns o UNCHANGED
  • If frozen is True:
    • If o is an instance of Private, returns freeze(o) (FrozenPrivate)
    • If o is an instance of Protected, returns freeze(o) (FrozenProtected)
    • Otherwise: If frozen is True, returns FrozenPrivate; returns Private otherwise
protect(
    o: object frozen: bool = False,
    dynamic: bool = True,
    hide_private: bool = False,
    ro_data: bool = False,
    ro_method: bool = True,
    ro: List[str] = [],
    rw: List[str] = [],
    hide: List[str] = []
) -> object:
# o-->object to be wrapped

Returns-->Instance of FrozenProtected if frozen; Instance of Protected otherwise

If 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:

  • hide and hide_private are OR-ed
  • ro_method, ro_data and ro are OR-ed
  • rw is AND-ed, but rw of second protect overrides ro* of second protect but not the first protect.

In short, by calling protect() a second time (or multiple times):

  • Additoinal attributes can be hidden
  • Additional attributes can be made read-only
  • No previously hidden attribute will become visible
  • No previously read-only attribute will become mutable

Options: protect method arguments

Option Type Default Description Overrides
frozen bool False If True, no attributes can be changed, added or deleted
hide_private bool False If True, private vars of the form _var will be hidden
ro_data bool False Data (non-method) attributes will be immutable
Can override selectively with rw
ro_method bool True Method (callable) attributes will be immutable
Can override selectively with rw
ro list of str [ ] Attributes that will be immutable
Can override selectively with rw
rw list of str [ ] Attributes that will be mutable ro_data
ro_method
ro
hide list of str [ ]

Visibility and mutability of attributes with protect() method

Option Attribute Type Restricts Visibility Restricts Mutability
frozen Any NO YES
hide_private Private attributes YES YES (Indirect)
ro_data Data attributes NO YES
ro_method Method attributes NO YES
ro ANY NO YES
rw ANY NO YES
hide ANY YES YES (Indirect)

Classes

class diagram

Features of key classes

Wrapped

  • Visibility: No additional restrictions
  • Mutability: No additional restrictions

Frozen

  • Visibility: Does not additionally restrict visibility of any attributes in wrapped object accessed through wrapping object
  • Mutability: Prevents modification of ANY attribute

Private

  • Visibility:
    • Cannot access traditionally 'private' mangled python attributes
    • Cannot modify traditionally private attributes (form 'var')
    • Attributes not part of dir(wrapped_object) are not visible
  • Mutability:
    • The following attributes of wrapped object are NEVER writeable: __class__, __dict__, __delattr__, __setattr__, __slots__, __getattribute__
    • Traditional (mangled) Python private vars are ALWAYS hidden
    • Private vars (form _var) will be read-only
    • Attributes cannot be added or removed
    • Attributes that are properties are ALWAYS visible AND WRITABLE (except if 'frozen' is used)
      • Properties indicate an intention of class author to expose them
      • Whether they are actually writable depends on whether class author implemented property.setter

FrozenPrivate

  • Visibility: Same as Private
  • Mutability: Prevents modification of ANY attribute

Protected

  • Features of Private PLUS allows further restriction of:
    • Which attributes are VISIBLE
    • Which attributes are WRITEABLE
  • Default settings:
    • Features of Private - see above
    • dynamic == True Attribute additions, deletions, type changes automatically visible
    • ro_method == True: Method attributes will be read-only
    • All other non-private data attributes are read-write

FrozenProtected

  • Features of Protected PLUS prevents modification of ANY attribute

API

Wrapping API

freeze

freeze(o: object) -> Frozen:
  • If o is immutable (e.g. int , string), returns o UNCHANGED
  • If o is Wrapped, returns o UNCHANGED if object WRAPPPED INSIDE o is immutable, returns Frozen otherwise
  • If o is Frozen, returns o UNCHANGED
  • If o is FrozenPrivate, FrozenProtected or FrozenPrivacyDict, returns o UNCHANGED
  • If o is Private, returns FrozenPrivate
  • If o is Protected, returns FrozenProtected
  • Otherwise, returns Frozen

Object returned prevents modification of ANY attribute

private

private(o: object, frozen: bool = False) -> object:
  • If frozen is False:
    • If o is an instance of Private, returns o UNCHANGED
    • If 'o' is an instance of Protected, returns o UNCHANGED
  • If frozen is True:
    • If o is an instance of Private, returns freeze(o) (FrozenPrivate)
    • If o is an instance of Protected, returns freeze(o) (FrozenProtected)
    • Otherwise: If frozen is True, returns FrozenPrivate; returns Private otherwise

protect

protect(
    o: object frozen: bool = False,
    dynamic: bool = True,
    hide_private: bool = False,
    ro_data: bool = False,
    ro_method: bool = True,
    ro: List[str] = [],
    rw: List[str] = [],
    hide: List[str] = []
) -> object:
# o-->object to be wrapped

Returns-->Instance of FrozenProtected if frozen; Instance of Protected otherwise

If 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:

  • hide and hide_private are OR-ed
  • ro_method, ro_data and ro are OR-ed
  • rw is AND-ed, but rw of second protect overrides ro* of second protect but not the first protect.

In short, by calling protect() a second time (or multiple times):

  • Additoinal attributes can be hidden
  • Additional attributes can be made read-only
  • No previously hidden attribute will become visible
  • No previously read-only attribute will become mutable

Options: protect method arguments

Option Type Default Description Overrides
frozen bool False If True, no attributes can be changed, added or deleted
hide_private bool False If True, private vars of the form _var will be hidden
ro_data bool False Data (non-method) attributes will be immutable
Can override selectively with rw
ro_method bool True Method (callable) attributes will be immutable
Can override selectively with rw
ro list of str [ ] Attributes that will be immutable
Can override selectively with rw
rw list of str [ ] Attributes that will be mutable ro_data
ro_method
ro
hide list of str [ ]

Visibility and mutability of attributes with protect() method

Option Attribute Type Restricts Visibility Restricts Mutability
frozen Any NO YES
hide_private Private attributes YES YES (Indirect)
ro_data Data attributes NO YES
ro_method Method attributes NO YES
ro ANY NO YES
rw ANY NO YES
hide ANY YES YES (Indirect)

wrap

wrap(o: object) -> Wrapped:
  • Should behave just like the wrapped object, except following attributes cannot be modified: __getattribute__, __delattr__, __setattr__, __slots__
  • Explicitly does NOT support pickling, and will raise pickle.PicklingError
  • Does NOT protect CLASS (or __class__) of wrapped object from modification
  • Does NOT protect __dict__ or __slots__

Useful for testing if wrapping is failing for a particular type of object

Checking types of wrapped objects

isfrozen

isfrozen(x: object) -> bool

x was created using freeze() or private(o, frozen=True) or protect(o, frozen=True)

isimmutable

isimmutable(x: object) -> bool

x is known to be immutable

isprivate

isprivate(x: object) -> bool

x was created using private()

isprotected

isprotected(x: object) -> bool

x was created using protect()

Checking properties of objects inside wrapped objects

contains

contains(w: object, o: object) -> bool

If w is a wrapped object (iswrapped(w) is True), returns whether w wraps o Otherwise unconditionally returns False

help_protected

help_protected(x: object) -> None

If x wraps o, executes help(o) Otherwise executes h_elp(x)_

id_protected

id_protected(x: object) -> int

if x is a wrapped object (iswrapped(x) is True) and x wraps o, returns id(o) Otherwise returns id(x)

isinstance_protected

isinstance_protected(x: object, t: type) -> bool

If x is a wrapped object (iswrapped(x) is True) and x wraps o, returns isinstance(o, t) Otherwise returns isinstance(x, t)

isreadonly

isreadonly(x: object, a: str) -> bool

If 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 This 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 If x is not a wrapped object (iswrapped(x) is False) , unconditionally returns False

instance_of_protected

instance_of_protected(x: object, o: object) -> bool

If 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)) If x is not a wrapped object - iswrapped(x) == False - instance_of_protected(x, o) returns isinstance(x, o)

isvisible

isvisible(x: object, a: str) -> bool

Returns False if and only if iswrapped(x) is True AND x makes attribute a invisible if present in wrapped object
This 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

If x is not a wrapped object, unconditionally returns False

same_class_protected

same_class_protected(c: type, w: object) -> bool

If iswrapped(w) and w wraps o: Returns (c is type(o))
Otherwise: returns (c is type(w))

subclass_of_protected

subclass_of_protected(x: object, w: object) -> bool

If iswrapped(w) and w wraps o: Returns issubclass(x, type(o))
Otherwise: returns issubclass(x, w)

pyprotect module metadata

immutable_builtin_attributes

immutable_builtin_attributes() -> Set[str]

Returns-->set of str: attributes in builtins that are immutable Used in unit tests

always_delegated_attributes

always_delegated_attributes() -> set(str)

Attributes that are always delegated to wrapped object

attribute_protected

attribute_protected() -> str

Name of special attribute in Wrapped objects

hidden_pickle_attributes

hidden_pickle_attributes() -> set(str)

Attributes that are never visible in object 'o' if iswrapped(o) - to disallow pickling

never_writeable

never_writeable() -> set(str)

Attributes that are never writeable in object o if iswrapped(o)

never_writeable_private

never_writeable_private() -> set(str)

Attributes that are never writeable in object o if isprivate(o)

Calling wrap operations multiple times

In the table below:

  • The left-most column shows starting state.
  • The top row shows operation applied to the starting state.
  • The intersecting cell shows the result.
  • UNCH represents operation returning the starting state unchanged
Operation 🡆
On type 🡇
wrap freeze private private
+ frozen
protect protect
+ frozen
Ordinary object
iswrapped(x) is False
Wrapped Frozen
(2)
Private FrozenPrivate Protected FrozenProtected
Wrapped UNCH Frozen
(2)
Private FrozenPrivate Protected FrozenProtected
Frozen Wrapped
(2)
UNCH
(2)
FrozenPrivate FrozenPrivate FrozenProtected FrozenProtected
Private UNCH FrozenPrivate UNCH FrozenPrivate Protected FrozenProtected
FrozenPrivate UNCH UNCH UNCH UNCH FrozenProtected FrozenProtected
Protected UNCH FrozenProtected UNCH FrozenProtected Protected
(1)
FrozenProtected
(1)
FrozenProtected UNCH UNCH UNCH UNCH FrozenProtected
(1)
FrozenProtected
(1)
  1. protect() applied twice will merge the protect() rules, enforcing the most restrictive combination among the two sets of protect() options:
  • hide and hide_private are OR-ed
  • ro_method, ro_data and ro are OR-ed
  • rw is AND-ed, but rw of second protect overrides ro* of second protect but not the first protect.

In short, by calling protect() a second time (or multiple times): - Additoinal attributes can be hidden - Additional attributes can be made read-only but: - No previously hidden attribute will become visible - No previously read-only attribute will become mutable

  1. 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.

For all other objects x, having isimmutable(x) == False, freeze(x) will return a Frozen object having iswrapped(freeze(x)) == True

For all other wrapped objects w, created with private(x) or protect(x), freeze(w) will always return a Wrapped object with iswrapped(w) == True

Python rules for attributes of type 'property':

  • Properties are defined in the CLASS, and cannot be changed in the object INSTANCE
  • Properties cannot be DELETED
  • Properties cannot be WRITTEN to unless property has a 'setter' method defined in the CLASS
  • These rules are implemented by the python language (interpreter) and Protected class does not enforce or check

What kind of python objects can be wrapped?

Pretty 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

Work in progress

Changelog

Jan-20-2022

  • Project name on github changed to pyprotect to match the name of the module. This has been long-pending. The old github link redirects to the new project name.

Jan-15-2022

  • Started signing commits with my GPG key and displaying 'verified' for signed commits

Dec-08-2022

A 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'.

hide_all, hide_method, hide_dunder So-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).

hide_data In 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.

ro_dunder Seems 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'.

ro_all Is unnecessary, since 'frozen' can be used instead.

add In 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.

show It is unnecessary, since all attributes are visible by default in Python. Only 'hide' or 'hide_private' will hide any attributes.

This leaves the following (incidentally also reducing testing load):

- Visibility:
	- hide_private
	- hide
- Mutability:
	- ro_data
	- ro_method
	- ro
	- rw
	- frozen
- Behavior:
	- dynamic

pyprotect's People

Contributors

sundarnagarajan avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

pyprotect's Issues

Alpine linux 3.15 on pypy3 test_52_numeric_ops_float fails

ERROR: test_52_numeric_ops_float (__main__.test_pyprotect)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_pyprotect.py", line 1137, in test_52_numeric_ops_float
    assert(ceil(w1) == 101)
  File "Proxy.pxi", line 114, in pyprotect.protected.Proxy.__ceil__
AttributeError: 'CF' object has no attribute '__ceil__'. Did you mean: __bool__?

Not yet ivnestigated.
The same test does not fail on PY3 / PY2 / PYPY2 on ubuntu jammy

inplace_build.sh PY2 extension may be present but not working on chosen distro

  • This affects only PY2
  • Even if $TARGET is present, it may not work for chosen distro

This is noticed (atleast) between alpine and Ubuntu because:

  • PY2 just names the C-extension '<extension_name>.so' without any qualfier specifying:
    • Python implementation - e.g. cpython | pypy38-pp73 | pypy73
    • Architecture - e.g. x86_64
    • libc used - e.g. linux-gnu | linux-musl

Solution is to check that the PY2 extension .so can be loaded by testing with ldd. If extension cannot be loaded, rebuild by setting REBUILD_REQUIRED=1

python 3.6.15 test_13_wrapping_module fails

FAIL: test_13_wrapping_module (main.test_pyprotect)

Traceback (most recent call last):
File "test_pyprotect.py", line 879, in test_13_wrapping_module
t.module_attr_not_in_dir
AssertionError: Exception not raised

PYPY2 10 tests fail after moving to Cython 3.0.010a11

All fail with:

  File "python_visible.pxi", line 18, in pyprotect.protected.id_protected
TypeError: Expected int, got long

Test cases:

  • test_01_multiwrap_1300_tests - line 104
  • test_02_wrap_objects - line 110
  • test_03_private_objects - line 118
  • test_04_protect_objects - line 128
  • test_05_private_vs_wrapped - line 143
  • test_06_private_vs_wrapped_py2_oldstyle - line 233
  • test_07_protected_options - line 346
  • test_51_numeric_ops_int - line 1029
  • test_52_numeric_ops_float - line 1114
  • test_63_complex - line 1539

still some bug in python 3.8

thanks for fixing the code to work with python 3.8
i though face another problem when i run the example

error

ImportError: cannot import name 'Protected' from 'protected_class' (/usr/local/lib/python3.8/site-packages/protected_class.cpython-38-x86_64-linux-gnu.so)

on the other side some functions can be import but i'm trying to understand how this works

class MyClass(object):
    def __init__(self):
        self.__hidden = 1
        self._private = 2
        self.public = 3


# Get an instance of your class
myinst = MyClass()

# import + ONE line to wrap and protect class attributes
from protected_class import protect
wrapped = protect(myinst, hide_data = True,hide_all = True , hide_dunder = True, hide_private = True)

variables = f"{myinst.public} - {myinst._private} - {myinst._MyClass__hidden}"
print(variables)

prints 3 - 2 - 1 but is this the expected behaviour, i thought i was protected

Am i doing this right ?

thanks

Support SCRIPTS_DIR in config.sh

(Only) for maximizing REUSABILITY of scripts in different projects - in case scripts dir is already used by project

Affects:

  • config.sh
  • host_build_in_place.sh
  • host_test.sh
  • root_install_test_in_docker.sh
  • venv_test_install_inplace.sh

python 3.8

I'm afraid it doesn't work with python 3.8

ERROR: Command errored out with exit status 1:
   command: /usr/local/bin/python3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-3b2fk551/protected-class_bbc11fa2be1945589dbe51b7d2887fab/setup.py'"'"'; __file__='"'"'/tmp/pip-install-3b2fk551/protected-class_bbc11fa2be1945589dbe51b7d2887fab/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-lu2ks25p
       cwd: /tmp/pip-install-3b2fk551/protected-class_bbc11fa2be1945589dbe51b7d2887fab/
  Complete output (249 lines):
  running bdist_wheel
  running build
  running build_ext
  building 'protected_class' extension
  creating build
  creating build/temp.linux-x86_64-3.8
  creating build/temp.linux-x86_64-3.8/src
  creating build/temp.linux-x86_64-3.8/src/c
  gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/usr/local/include/python3.8 -c src/c/protected_class.c -o build/temp.linux-x86_64-3.8/src/c/protected_class.o
  src/c/protected_class.c: In function ‘PyInit_protected_class’:
  src/c/protected_class.c:38863:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_Wrapped.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:38881:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_Frozen.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:38899:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_PrivacyDict.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:38917:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_FrozenPrivacyDict.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:38938:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_Private.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:38956:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_FrozenPrivate.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:38982:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_Protected.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39000:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class_FrozenProtected.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39015:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class___pyx_scope_struct____iter__.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39018:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class___pyx_scope_struct_1_next.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39021:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class___pyx_scope_struct_2_iteritems.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39024:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class___pyx_scope_struct_3_iterkeys.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39027:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_type_15protected_class___pyx_scope_struct_4_itervalues.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39030:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_scope_struct____Pyx_CFunc_object____Wrapped____object___to_py.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c:39033:3: warning: ‘tp_print’ is deprecated [-Wdeprecated-declarations]
     __pyx_scope_struct____Pyx_CFunc_object____Private____object____object___to_py.tp_print = 0;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from /usr/local/include/python3.8/object.h:746,
                   from /usr/local/include/python3.8/pytime.h:6,
                   from /usr/local/include/python3.8/Python.h:85,
                   from src/c/protected_class.c:4:
  /usr/local/include/python3.8/cpython/object.h:260:30: note: declared here
       Py_DEPRECATED(3.8) int (*tp_print)(PyObject *, FILE *, int);
                                ^~~~~~~~
  src/c/protected_class.c: In function ‘__Pyx__ExceptionSave’:
  src/c/protected_class.c:42066:21: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_type’; did you mean ‘curexc_type’?
       *type = tstate->exc_type;
                       ^~~~~~~~
                       curexc_type
  src/c/protected_class.c:42067:22: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_value’; did you mean ‘curexc_value’?
       *value = tstate->exc_value;
                        ^~~~~~~~~
                        curexc_value
  src/c/protected_class.c:42068:19: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_traceback’; did you mean ‘curexc_traceback’?
       *tb = tstate->exc_traceback;
                     ^~~~~~~~~~~~~
                     curexc_traceback
  src/c/protected_class.c: In function ‘__Pyx__ExceptionReset’:
  src/c/protected_class.c:42075:24: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_type’; did you mean ‘curexc_type’?
       tmp_type = tstate->exc_type;
                          ^~~~~~~~
                          curexc_type
  src/c/protected_class.c:42076:25: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_value’; did you mean ‘curexc_value’?
       tmp_value = tstate->exc_value;
                           ^~~~~~~~~
                           curexc_value
  src/c/protected_class.c:42077:22: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_traceback’; did you mean ‘curexc_traceback’?
       tmp_tb = tstate->exc_traceback;
                        ^~~~~~~~~~~~~
                        curexc_traceback
  src/c/protected_class.c:42078:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_type’; did you mean ‘curexc_type’?
       tstate->exc_type = type;
               ^~~~~~~~
               curexc_type
  src/c/protected_class.c:42079:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_value’; did you mean ‘curexc_value’?
       tstate->exc_value = value;
               ^~~~~~~~~
               curexc_value
  src/c/protected_class.c:42080:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_traceback’; did you mean ‘curexc_traceback’?
       tstate->exc_traceback = tb;
               ^~~~~~~~~~~~~
               curexc_traceback
  src/c/protected_class.c: In function ‘__Pyx__GetException’:
  src/c/protected_class.c:42490:24: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_type’; did you mean ‘curexc_type’?
       tmp_type = tstate->exc_type;
                          ^~~~~~~~
                          curexc_type
  src/c/protected_class.c:42491:25: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_value’; did you mean ‘curexc_value’?
       tmp_value = tstate->exc_value;
                           ^~~~~~~~~
                           curexc_value
  src/c/protected_class.c:42492:22: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_traceback’; did you mean ‘curexc_traceback’?
       tmp_tb = tstate->exc_traceback;
                        ^~~~~~~~~~~~~
                        curexc_traceback
  src/c/protected_class.c:42493:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_type’; did you mean ‘curexc_type’?
       tstate->exc_type = local_type;
               ^~~~~~~~
               curexc_type
  src/c/protected_class.c:42494:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_value’; did you mean ‘curexc_value’?
       tstate->exc_value = local_value;
               ^~~~~~~~~
               curexc_value
  src/c/protected_class.c:42495:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_traceback’; did you mean ‘curexc_traceback’?
       tstate->exc_traceback = local_tb;
               ^~~~~~~~~~~~~
               curexc_traceback
  src/c/protected_class.c: In function ‘__Pyx__ExceptionSwap’:
  src/c/protected_class.c:44501:24: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_type’; did you mean ‘curexc_type’?
       tmp_type = tstate->exc_type;
                          ^~~~~~~~
                          curexc_type
  src/c/protected_class.c:44502:25: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_value’; did you mean ‘curexc_value’?
       tmp_value = tstate->exc_value;
                           ^~~~~~~~~
                           curexc_value
  src/c/protected_class.c:44503:22: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_traceback’; did you mean ‘curexc_traceback’?
       tmp_tb = tstate->exc_traceback;
                        ^~~~~~~~~~~~~
                        curexc_traceback
  src/c/protected_class.c:44504:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_type’; did you mean ‘curexc_type’?
       tstate->exc_type = *type;
               ^~~~~~~~
               curexc_type
  src/c/protected_class.c:44505:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_value’; did you mean ‘curexc_value’?
       tstate->exc_value = *value;
               ^~~~~~~~~
               curexc_value
  src/c/protected_class.c:44506:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘exc_traceback’; did you mean ‘curexc_traceback’?
       tstate->exc_traceback = *tb;
               ^~~~~~~~~~~~~
               curexc_traceback
  error: command 'gcc' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for protected-class

Tests for PY3-only features / keywords

Just adding as-is to existing script will break PY2 testing - since PY2 interpreter will not load the script with unknown keywords even if protected with "if PY2"

Options:

  • Separate top-level test script
  • Separate PY3-only test module selectively loaded within one or more test cases
  • Using "eval" or the like

Python3-only test cases:

  • Test case wrapping async context manager
    • aenter, aexit
    • See link
  • Test case wrapping coroutine
    • 'send', 'throw', close'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.