Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Python design kit: interfaces, declared exception throws, class members accessibility levels (private and protected methods for humans).
accessify
is a Python
design kit that provides:
that could be combined with each other to make your code slim and this library usage more justified.
Access level modifiers determine whether other classes can use a particular field or invoke a particular method.
Accessibility levels are presented from the box in the languages like C++
, C#
and Java
.
class Car
{
private string StartEngine()
{
// Code here.
}
}
But Python
does not have this in the same way.
We're all consenting adults here
that is the part of the Python philosophy
that relies on human factor instead of the interpreter.Python convention
that is to use an underscore prefix for protected and private members, that is a bit ugly.
Isn't it? For instance, for the following piece of code that provides class a private member.class Car:
def __start_engine(self, *args, **kwargs):
pass
class Car:
def _start_engine(self, *args, **kwargs):
pass
def __start_engine(self, *args, **kwargs):
pass
car = Car()
car._start_engine()
car._Car__start_engine()
An interface is a contract specifying a set of methods and properties which required to be available on any implementing class.
If the class implements an interface, but does not realize its method, corresponding errors should be raised. Interfaces are presented from the box in
the languages like C++
, C#
and Java
.
interface HumanInterface
{
public string EatFood();
}
class Human : HumanInterface
{
public string EatFood()
{
// Code here.
}
}
But Python
does not have this in the same way.
Python
.Using pip install the package from the PyPi.
$ pip3 install accessify
In this example, the Car
class contains a private member named start_engine
. As a private member, they cannot be accessed
except by member methods. The private member start_engine
is accessed only by way of a public method called run
.
from accessify import private
class Car:
@private
def start_engine(self):
return 'Engine sound.'
def run(self):
return self.start_engine()
if __name__ == '__main__':
car = Car()
assert 'Engine sound.' == car.run()
car.start_engine()
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/access/private.py", line 24, in <module>
car.start_engine()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py", line 92, in private_wrapper
class_name=instance_class.__name__, method_name=method.__name__,
accessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is inaccessible due to its protection level
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhASP > private.py
$ python3 private.py
In this example, the Car
class contains a private member named start_engine
. As a private member, they cannot be accessed
from the child classes, Tesla
in our case. So overridden method run
by Tesla
class cannot use the parent's start_engine
member.
from accessify import private
class Car:
@private
def start_engine(self):
return 'Engine sound.'
class Tesla(Car):
def run(self):
return self.start_engine()
if __name__ == '__main__':
tesla = Tesla()
tesla.run()
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/inheritance/private.py", line 23, in <module>
tesla.run()
File "examples/inheritance/private.py", line 18, in run
return self.start_engine()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py", line 94, in private_wrapper
class_name=class_contain.__name__, method_name=method.__name__,
accessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is inaccessible due to its protection level
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhASX > inheritence_private.py
$ python3 inheritence_private.py
In this example, the Car
class contains a protected member named start_engine
. As a protected member, they cannot be accessed
except by member methods. The protected member start_engine
is accessed only by way of a public method called run
.
from accessify import protected
class Car:
@protected
def start_engine(self):
return 'Engine sound.'
def run(self):
return self.start_engine()
if __name__ == '__main__':
car = Car()
assert 'Engine sound.' == car.run()
car.start_engine()
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/access/protected.py", line 21, in <module>
car.start_engine()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py", line 134, in protected_wrapper
class_name=instance_class.__name__, method_name=method.__name__,
accessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is inaccessible due to its protection level
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhASM > protected.py
$ python3 protected.py
In this example, the Car
class contains a protected member named start_engine
. As a protected member, they can be accessed
from the child classes, Tesla
in our case. So overridden method run
by Tesla
class can use the parent's start_engine
member.
from accessify import protected
class Car:
@protected
def start_engine(self):
return 'Engine sound.'
class Tesla(Car):
def run(self):
return self.start_engine()
if __name__ == '__main__':
tesla = Tesla()
assert 'Engine sound.' == tesla.run()
The code will work without errors.
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhASD > inheritence_protected.py
$ python3 inheritence_protected.py
accessify
decorator removes private and protected members from class dir.from accessify import accessify, private
@accessify
class Car:
@private
def start_engine(self):
return 'Engine sound.'
if __name__ == '__main__':
car = Car()
assert 'start_engine' not in dir(car)
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhASy > dir.py
$ python3 dir.py
In this example, there is an interface called HumanInterface
that contains two methods love
and eat
. Also, there is
a class Human
that implements the interface but missed method «eat», so the corresponding error should be raised.
from accessify import implements
class HumanInterface:
@staticmethod
def eat(food, *args, allergy=None, **kwargs):
pass
if __name__ == '__main__':
@implements(HumanInterface)
class Human:
pass
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/interfaces/single.py", line 18, in <module>
@implements(HumanInterface)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 66, in decorator
interface_method_arguments=interface_method.arguments_as_string,
accessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanInterface.eat(food, args, allergy, kwargs)
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhh2V > single_method.py
$ python3 single_method.py
In this example, there is an interface called HumanInterface
that contains two methods love
and eat
. Also, there is
a class Human
that implements the interface but missed 3 of 4 arguments for method «eat», so the corresponding error should be raised.
from accessify import implements
class HumanInterface:
@staticmethod
def eat(food, *args, allergy=None, **kwargs):
pass
if __name__ == '__main__':
@implements(HumanInterface)
class Human:
@staticmethod
def eat(food):
pass
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/interfaces/single_arguments.py", line 16, in <module>
@implements(HumanInterface)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 87, in decorator
interface_method_arguments=interface_method.arguments_as_string,
accessify.errors.InterfaceMemberHasNotBeenImplementedWithMismatchedArgumentsException: class Human implements interface member HumanInterface.eat(food, args, allergy, kwargs) with mismatched arguments
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhh2w > single_arguments.py
$ python3 single_arguments.py
In this example, there is an interface called HumanInterface
that contains two methods love
and eat
. Also, there is
a class Human
that implements the interface but missed private access modifier type for method «eat», so the corresponding
error should be raised.
from accessify import implements, private
class HumanInterface:
@private
@staticmethod
def eat(food, *args, allergy=None, **kwargs):
pass
if __name__ == '__main__':
@implements(HumanInterface)
class Human:
@staticmethod
def eat(food, *args, allergy=None, **kwargs):
pass
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/interfaces/single_access.py", line 18, in <module>
@implements(HumanInterface)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 77, in decorator
interface_method_name=interface_method.name,
accessify.errors.ImplementedInterfaceMemberHasIncorrectAccessModifierException: Human.eat(food, args, allergy, kwargs) mismatches HumanInterface.eat() member access modifier.
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhh2r > single_access.py
$ python3 single_access.py
In this example, there are an interface HumanSoulInterface
that contains a method called love
and interface HumanBasicsInterface
that
contains a method called eat
. Also, there is a class Human
that implements method love
from the first interface, but
missed method «eat» from the second one, so the corresponding error should be raised.
from accessify import implements
class HumanSoulInterface:
def love(self, who, *args, **kwargs):
pass
class HumanBasicsInterface:
@staticmethod
def eat(food, *args, allergy=None, **kwargs):
pass
if __name__ == '__main__':
@implements(HumanSoulInterface, HumanBasicsInterface)
class Human:
def love(self, who, *args, **kwargs):
pass
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/interfaces/multiple.py", line 19, in <module>
@implements(HumanSoulInterface, HumanBasicsInterface)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 66, in decorator
interface_method_arguments=interface_method.arguments_as_string,
accessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanBasicsInterface.eat(food, args, allergy, kwargs)
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhh2o > multiple.py
$ python3 multiple.py
In this example, exception HumanDoesNotExistsError
and exception HumanAlreadyInLoveError
are declared to be raised by
the Human
class method called love
, but method missed to raise the second exception, so the corresponding error should be raised.
from accessify import implements, throws
class HumanDoesNotExistsError(Exception):
pass
class HumanAlreadyInLoveError(Exception):
pass
class HumanInterface:
@throws(HumanDoesNotExistsError, HumanAlreadyInLoveError)
def love(self, who, *args, **kwargs):
pass
if __name__ == '__main__':
@implements(HumanInterface)
class Human:
def love(self, who, *args, **kwargs):
if who is None:
raise HumanDoesNotExistsError('Human whom need to love does not exist.')
The code above will produce the following traceback.
Traceback (most recent call last):
File "examples/interfaces/throws.py", line 21, in <module>
@implements(HumanInterface)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 103, in decorator
class_method_arguments=class_member.arguments_as_string,
accessify.errors.DeclaredInterfaceExceptionHasNotBeenImplementedException: Declared exception HumanAlreadyInLoveError by HumanInterface.love() member has not been implemented by Human.love(self, who, args, kwargs)
Test it out using the examples.
Get the example that contains the code above by curl
and run it by python3
.
$ curl -L https://git.io/fhh26 > throws.py
$ python3 throws.py
You can disable all accessify
checks. For instance, in the production, when you shouldn't check it because it already was checked
in the development. Use the following environment variable then:
export DISABLE_ACCESSIFY=True
Clone the project and install requirements:
$ git clone git@github.com:dmytrostriletskyi/accessify.git && cd accessify
$ pip3 install -r requirements-dev.txt
$ pip3 install -r requirements-tests.txt
If you prefer working with the Docker and wanna easily change Python
environments, follow:
$ git clone git@github.com:dmytrostriletskyi/accessify.git && cd accessify
$ export ACCESSIFY_PYTHON_VERSION=3.4
$ docker build --build-arg ACCESSIFY_PYTHON_VERSION=$ACCESSIFY_PYTHON_VERSION -t accessify . -f Dockerfile-python3.x
$ docker run -v $PWD:/accessify --name accessify accessify
Enter the container bash, check Python
version and run tests:
$ docker exec -it accessify bash
$ root@36a8978cf100:/accessify# python --version
$ root@36a8978cf100:/accessify# pytest -vv tests
Clean container and images with the following command:
$ docker rm $(docker ps -a -q) -f
$ docker rmi $(docker images -q) -f
When you will make changes, ensure your code pass the checkers and is covered by tests using pytest.
If you are new for the contribution, please read:
Check it out to familiarize yourself with class members accessibility levels:
FAQs
Python design kit: interfaces, declared exception throws, class members accessibility levels (private and protected methods for humans).
We found that accessify demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.