{ "info": { "author": "Dmytro Striletskyi", "author_email": "dmytro.striletskyi@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "# accessify\n\n[![Release](https://img.shields.io/github/release/dmytrostriletskyi/accessify.svg)](https://github.com/dmytrostriletskyi/accessify/releases)\n[![PyPI version shields.io](https://img.shields.io/pypi/v/accessify.svg)](https://pypi.python.org/pypi/accessify/)\n[![Build Status](https://travis-ci.com/dmytrostriletskyi/accessify.svg?branch=develop)](https://travis-ci.com/dmytrostriletskyi/accessify)\n[![codecov](https://codecov.io/gh/dmytrostriletskyi/design-kit/branch/develop/graph/badge.svg)](https://codecov.io/gh/dmytrostriletskyi/design-kit)\n\n[![Downloads](https://pepy.tech/badge/accessify)](https://pepy.tech/project/accessify)\n[![PyPI license](https://img.shields.io/pypi/l/accessify.svg)](https://pypi.python.org/pypi/accessify/)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/accessify.svg)](https://pypi.python.org/pypi/accessify/)\n\n[![Habrahabr](https://img.shields.io/badge/Post-Habrahabr-brightgreen.svg)](https://habr.com/ru/post/443192/)\n\n * [Getting started](#getting-started)\n * [What is accessify](#what-is-accessify)\n * [Access modifiers](#getting-started-access-modifiers)\n * [Motivation](#getting-started-access-modifiers-motivation)\n * [Interfaces](#getting-started-interfaces)\n * [Motivation](#getting-started-interfaces-motivation)\n * [How to install](#how-to-install)\n * [Usage](#usage)\n * [Access modifiers](#usage-access-modifiers)\n * [Private](#private)\n * [Protected](#protected)\n * [Other features](#other-features)\n * [Interfaces](#usage-interfaces)\n * [Single interface](#single-interface)\n * [Multiple interfaces](#multiple-interfaces)\n * [Exception throws declaration](#exception-throws-declaration)\n * [Disable checking](#disable-checking)\n * [Contributing](#contributing)\n * [References](#references)\n\n## Getting started\n\n### What is accessify\n\n`accessify` is a `Python` design kit that provides:\n* interfaces, \n* declared exceptions throws, \n* class members accessibility levels.\n\nthat could be combined with each other to make your code slim and this library usage more justified.\n\n

Access modifiers

\n\nAccess level modifiers determine whether other classes can use a particular field or invoke a particular method.\nAccessibility levels are presented from the box in the languages like `C++`, `C#` and `Java`. \n\n```csharp\nclass Car \n{\n private string StartEngine()\n {\n // Code here.\n }\n}\n```\n\nBut `Python` does not have this in the same way.\n\n

Motivation

\n\n* `We're all consenting adults here` that is the part of the `Python philosophy` that relies on human factor instead of the interpreter.\n* There is a `Python convention` that is to use an underscore prefix for protected and private members, that is a bit ugly. \nIsn't it? For instance, for the following piece of code that provides class a private member.\n\n```python\nclass Car:\n\n def __start_engine(self, *args, **kwargs):\n pass\n```\n\n* Moreover, private and protected methods could be easily accessed outside the class. This is really a point to postpone the \ncorrect design of the system to the backlog, increasing the technical debt.\n\n ```python\nclass Car:\n\n def _start_engine(self, *args, **kwargs):\n pass\n \n def __start_engine(self, *args, **kwargs):\n pass\n\n\ncar = Car()\ncar._start_engine()\ncar._Car__start_engine()\n```\n\n

Interfaces

\n\nAn interface is a contract specifying a set of methods and properties which required to be available on any implementing class.\nIf the class implements an interface, but does not realize its method, corresponding errors should be raised. Interfaces are presented from the box in \nthe languages like `C++`, `C#` and `Java`. \n\n```csharp\ninterface HumanInterface\n{\n public string EatFood();\n}\n\nclass Human : HumanInterface\n{\n public string EatFood()\n {\n // Code here.\n }\n}\n```\n\nBut `Python` does not have this in the same way.\n\n

Motivation

\n\n* The interface makes checks during the implementation creation, but not actually while execution like [abc](https://docs.python.org/3/library/abc.html) module in `Python`.\n* The interface requires that implementation's method arguments match with arguments declared in interfaces, [abc](https://docs.python.org/3/library/abc.html) \u2014 not.\n* A lot of libraries that provide interfaces are no longer supported.\n* A lot of libraries that provide interfaces require you to write a lot of code to use its functionality, this library \u2014 not.\n\n### How to install\n\nUsing [pip](https://pypi.org/project/pip) install the package from the [PyPi](https://pypi.org/project/accessify).\n\n```bash\n$ pip3 install accessify\n```\n\n## Usage\n\n

Access modifiers

\n\n#### Private\n\n* Private members are accessible only within the body of the class.\n\nIn this example, the `Car` class contains a private member named `start_engine`. As a private member, they cannot be accessed\nexcept by member methods. The private member `start_engine` is accessed only by way of a public method called `run`. \n\n```python\nfrom accessify import private\n\n\nclass Car:\n\n @private\n def start_engine(self):\n return 'Engine sound.'\n\n def run(self):\n return self.start_engine()\n\n\nif __name__ == '__main__':\n car = Car()\n\n assert 'Engine sound.' == car.run()\n\n car.start_engine()\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/access/private.py\", line 24, in \n car.start_engine()\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py\", line 92, in private_wrapper\n class_name=instance_class.__name__, method_name=method.__name__,\naccessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is inaccessible due to its protection level\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhASP > private.py\n$ python3 private.py\n```\n\n* Child classes cannot access parent private members.\n\nIn this example, the `Car` class contains a private member named `start_engine`. As a private member, they cannot be accessed\nfrom the child classes, `Tesla` in our case. So overridden method `run` by `Tesla` class cannot use the parent's `start_engine` member.\n\n```python\nfrom accessify import private\n\n\nclass Car:\n\n @private\n def start_engine(self):\n return 'Engine sound.'\n\n\nclass Tesla(Car):\n\n def run(self):\n return self.start_engine()\n\n\nif __name__ == '__main__':\n tesla = Tesla()\n tesla.run()\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/inheritance/private.py\", line 23, in \n tesla.run()\n File \"examples/inheritance/private.py\", line 18, in run\n return self.start_engine()\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py\", line 94, in private_wrapper\n class_name=class_contain.__name__, method_name=method.__name__,\naccessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is inaccessible due to its protection level\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhASX > inheritence_private.py\n$ python3 inheritence_private.py\n```\n\n#### Protected\n\n* A protected member is accessible within its class and by derived class instances.\n\nIn this example, the `Car` class contains a protected member named `start_engine`. As a protected member, they cannot be accessed\nexcept by member methods. The protected member `start_engine` is accessed only by way of a public method called `run`. \n\n```python\nfrom accessify import protected\n\n\nclass Car:\n\n @protected\n def start_engine(self):\n return 'Engine sound.'\n\n def run(self):\n return self.start_engine()\n\n\nif __name__ == '__main__':\n car = Car()\n\n assert 'Engine sound.' == car.run()\n\n car.start_engine()\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/access/protected.py\", line 21, in \n car.start_engine()\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py\", line 134, in protected_wrapper\n class_name=instance_class.__name__, method_name=method.__name__,\naccessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is inaccessible due to its protection level\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhASM > protected.py\n$ python3 protected.py\n```\n\n* Child classes have access to those protected members.\n\nIn this example, the `Car` class contains a protected member named `start_engine`. As a protected member, they can be accessed\nfrom the child classes, `Tesla` in our case. So overridden method `run` by `Tesla` class can use the parent's `start_engine` member.\n\n\n```python\nfrom accessify import protected\n\n\nclass Car:\n\n @protected\n def start_engine(self):\n return 'Engine sound.'\n\n\nclass Tesla(Car):\n\n def run(self):\n return self.start_engine()\n\n\nif __name__ == '__main__':\n tesla = Tesla()\n\n assert 'Engine sound.' == tesla.run()\n```\n\nThe code will work without errors.\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhASD > inheritence_protected.py\n$ python3 inheritence_protected.py\n```\n\n#### Other features\n\n* The `accessify` decorator removes private and protected members from class [dir](https://docs.python.org/3/library/functions.html#dir).\n\n```python\nfrom accessify import accessify, private\n\n\n@accessify\nclass Car:\n\n @private\n def start_engine(self):\n return 'Engine sound.'\n\nif __name__ == '__main__':\n car = Car()\n\n assert 'start_engine' not in dir(car)\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhASy > dir.py\n$ python3 dir.py\n```\n\n

Interfaces

\n\n#### Single interface\n\n* When you declare that class implements an interface, a class should implement **all methods** presented in the interface.\n\nIn this example, there is an interface called `HumanInterface` that contains two methods `love` and `eat`. Also, there is\na class `Human` that implements the interface but **missed method \u00abeat\u00bb**, so the corresponding error should be raised.\n\n```python\nfrom accessify import implements\n\n\nclass HumanInterface:\n\n @staticmethod\n def eat(food, *args, allergy=None, **kwargs):\n pass\n\n\nif __name__ == '__main__':\n\n @implements(HumanInterface)\n class Human:\n\n pass\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/interfaces/single.py\", line 18, in \n @implements(HumanInterface)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py\", line 66, in decorator\n interface_method_arguments=interface_method.arguments_as_string,\naccessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanInterface.eat(food, args, allergy, kwargs)\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhh2V > single_method.py\n$ python3 single_method.py\n```\n\n* When you declare that class implements an interface, a class should implement all methods that presented in the interface \nincluding **number, order and naming of the accepting arguments**. \n\nIn this example, there is an interface called `HumanInterface` that contains two methods `love` and `eat`. Also, there is\na class `Human` that implements the interface but **missed 3 of 4 arguments for method \u00abeat\u00bb**, so the corresponding error should be raised.\n\n```python\nfrom accessify import implements\n\n\nclass HumanInterface:\n\n @staticmethod\n def eat(food, *args, allergy=None, **kwargs):\n pass\n\n\nif __name__ == '__main__':\n\n @implements(HumanInterface)\n class Human:\n\n @staticmethod\n def eat(food):\n pass\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/interfaces/single_arguments.py\", line 16, in \n @implements(HumanInterface)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py\", line 87, in decorator\n interface_method_arguments=interface_method.arguments_as_string,\naccessify.errors.InterfaceMemberHasNotBeenImplementedWithMismatchedArgumentsException: class Human implements interface member HumanInterface.eat(food, args, allergy, kwargs) with mismatched arguments\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhh2w > single_arguments.py\n$ python3 single_arguments.py\n```\n\n* When you declare that class implements an interface, a class should implement all methods that presented in the interface \nincluding number, order and naming of the accepting arguments and **access modifier type**.\n\nIn this example, there is an interface called `HumanInterface` that contains two methods `love` and `eat`. Also, there is\na class `Human` that implements the interface but **missed private access modifier type for method \u00abeat\u00bb**, so the corresponding \nerror should be raised.\n\n```python\nfrom accessify import implements, private\n\n\nclass HumanInterface:\n\n @private\n @staticmethod\n def eat(food, *args, allergy=None, **kwargs):\n pass\n\n\nif __name__ == '__main__':\n\n @implements(HumanInterface)\n class Human:\n\n @staticmethod\n def eat(food, *args, allergy=None, **kwargs):\n pass\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/interfaces/single_access.py\", line 18, in \n @implements(HumanInterface)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py\", line 77, in decorator\n interface_method_name=interface_method.name,\naccessify.errors.ImplementedInterfaceMemberHasIncorrectAccessModifierException: Human.eat(food, args, allergy, kwargs) mismatches HumanInterface.eat() member access modifier.\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhh2r > single_access.py\n$ python3 single_access.py\n```\n\n#### Multiple interfaces\n\n* A class could implement multiple interfaces.\n* When you declare that class that implements a bunch of interfaces, a class should implement all method that presented in\neach interface including number, order and naming of the accepting arguments and access modifier type.\n\nIn this example, there are an interface `HumanSoulInterface` that contains a method called `love` and interface `HumanBasicsInterface` that \ncontains a method called `eat`. Also, there is a class `Human` that implements method `love` from the first interface, but \n**missed method \u00abeat\u00bb** from the second one, so the corresponding error should be raised.\n\n```python\nfrom accessify import implements\n\n\nclass HumanSoulInterface:\n\n def love(self, who, *args, **kwargs):\n pass\n\n\nclass HumanBasicsInterface:\n\n @staticmethod\n def eat(food, *args, allergy=None, **kwargs):\n pass\n\n\nif __name__ == '__main__':\n\n @implements(HumanSoulInterface, HumanBasicsInterface)\n class Human:\n\n def love(self, who, *args, **kwargs):\n pass\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/interfaces/multiple.py\", line 19, in \n @implements(HumanSoulInterface, HumanBasicsInterface)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py\", line 66, in decorator\n interface_method_arguments=interface_method.arguments_as_string,\naccessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanBasicsInterface.eat(food, args, allergy, kwargs)\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhh2o > multiple.py\n$ python3 multiple.py\n```\n\n#### Exception throws declaration\n\n* When you declare that interface method throws a particular exception, a class method that implement interface should \ncontain code in the body that raise this exception.\n* You can declare that the interface method throws multiple exceptions.\n\nIn this example, exception `HumanDoesNotExistsError` and exception `HumanAlreadyInLoveError` are declared to be raised by \nthe `Human` class method called `love` , but method **missed to raise the second exception**, so the corresponding error should be raised.\n\n```python\nfrom accessify import implements, throws\n\n\nclass HumanDoesNotExistsError(Exception):\n pass\n\n\nclass HumanAlreadyInLoveError(Exception):\n pass\n\n\nclass HumanInterface:\n\n @throws(HumanDoesNotExistsError, HumanAlreadyInLoveError)\n def love(self, who, *args, **kwargs):\n pass\n\n\nif __name__ == '__main__':\n\n @implements(HumanInterface)\n class Human:\n\n def love(self, who, *args, **kwargs):\n\n if who is None:\n raise HumanDoesNotExistsError('Human whom need to love does not exist.')\n```\n\nThe code above will produce the following traceback.\n\n```bash\nTraceback (most recent call last):\n File \"examples/interfaces/throws.py\", line 21, in \n @implements(HumanInterface)\n File \"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py\", line 103, in decorator\n class_method_arguments=class_member.arguments_as_string,\naccessify.errors.DeclaredInterfaceExceptionHasNotBeenImplementedException: Declared exception HumanAlreadyInLoveError by HumanInterface.love() member has not been implemented by Human.love(self, who, args, kwargs)\n```\n\nTest it out using the [examples](https://github.com/dmytrostriletskyi/accessify/tree/basic-accessibility-levels/examples).\nGet the example that contains the code above by `curl` and run it by `python3`.\n\n```bash\n$ curl -L https://git.io/fhh26 > throws.py\n$ python3 throws.py\n```\n\n## Disable checking\n\nYou can disable all `accessify` checks. For instance, in the production, when you shouldn't check it because it already was checked \nin the development. Use the following environment variable then:\n\n```bash\nexport DISABLE_ACCESSIFY=True\n```\n\n## Contributing\n\nClone the project and install requirements:\n\n```bash\n$ git clone git@github.com:dmytrostriletskyi/accessify.git && cd accessify\n$ pip3 install -r requirements-dev.txt\n$ pip3 install -r requirements-tests.txt\n```\n\nIf you prefer working with the [Docker](https://www.docker.com) and wanna easily change `Python` environments, follow:\n\n```bash\n$ git clone git@github.com:dmytrostriletskyi/accessify.git && cd accessify\n$ export ACCESSIFY_PYTHON_VERSION=3.4\n$ docker build --build-arg ACCESSIFY_PYTHON_VERSION=$ACCESSIFY_PYTHON_VERSION -t accessify . -f Dockerfile-python3.x\n$ docker run -v $PWD:/accessify --name accessify accessify\n```\n\nEnter the container bash, check `Python` version and run tests:\n\n```bash\n$ docker exec -it accessify bash\n$ root@36a8978cf100:/accessify# python --version\n$ root@36a8978cf100:/accessify# pytest -vv tests\n```\n\nClean container and images with the following command:\n\n```bash\n$ docker rm $(docker ps -a -q) -f\n$ docker rmi $(docker images -q) -f\n```\n\nWhen you will make changes, ensure your code pass [the checkers](https://github.com/dmytrostriletskyi/accessify/blob/basic-accessibility-levels/.travis.yml#L15) \nand is covered by tests using [pytest](https://docs.pytest.org/en/latest).\n\nIf you are new for the contribution, please read:\n\n* Read about pull requests \u2014 https://help.github.com/en/articles/about-pull-requests\n* Read how to provide pull request \u2014 https://help.github.com/en/articles/creating-a-pull-request-from-a-fork\n* Also the useful article about how to contribute \u2014 https://akrabat.com/the-beginners-guide-to-contributing-to-a-github-project/\n\n## References\n\nCheck it out to familiarize yourself with class members accessibility levels:\n\n* C# accessibility levels \u2014 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/accessibility-levels\n* Java accessibility levels \u2014 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html\n* Object-oriented programming interfaces \u2014 https://www.cs.utah.edu/~germain/PPS/Topics/interfaces.html\n* Interfaces in C# \u2014 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface\n* Interfaces in Java \u2014 https://docs.oracle.com/javase/tutorial/java/concepts/interface.html", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/dmytrostriletskyi/accessify", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "accessify", "package_url": "https://pypi.org/project/accessify/", "platform": "", "project_url": "https://pypi.org/project/accessify/", "project_urls": { "Homepage": "https://github.com/dmytrostriletskyi/accessify" }, "release_url": "https://pypi.org/project/accessify/0.3.1/", "requires_dist": null, "requires_python": "", "summary": "Python design kit: interfaces, declared exception throws, class members accessibility levels (private and protected methods for humans).", "version": "0.3.1" }, "last_serial": 4989889, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "dc10fa5bb33b9c92791b7a50f9708092", "sha256": "487956e9149debd7a0e4f96428daa666a79a9f656af85ff6a74ffbfcc757dfa9" }, "downloads": -1, "filename": "accessify-0.1.0.tar.gz", "has_sig": false, "md5_digest": "dc10fa5bb33b9c92791b7a50f9708092", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7809, "upload_time": "2019-03-02T18:29:10", "url": "https://files.pythonhosted.org/packages/2b/80/6b0493b59564926dae476cf8712d1802f05682a745a8c6baae1c5a3b1430/accessify-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "6cb220024c84ca7714cfec79d2bbd9f4", "sha256": "f4c468c3ffb4102189d60452a2121473b43a225db27cf273cd964d276bd62490" }, "downloads": -1, "filename": "accessify-0.2.0.tar.gz", "has_sig": false, "md5_digest": "6cb220024c84ca7714cfec79d2bbd9f4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17999, "upload_time": "2019-03-09T17:09:41", "url": "https://files.pythonhosted.org/packages/de/ba/33e2cb4052903b12b4ec4a9ecb21e5ee5e3ed2914e015ce1b401cc35fc2c/accessify-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "36d646f915116000870c0a1cc80582ca", "sha256": "c0c1510b5a1351cfa3601d34a220639c9132a0a8f7a7673e2b6d7f3179c5faec" }, "downloads": -1, "filename": "accessify-0.3.0.tar.gz", "has_sig": false, "md5_digest": "36d646f915116000870c0a1cc80582ca", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19009, "upload_time": "2019-03-19T21:38:17", "url": "https://files.pythonhosted.org/packages/71/ea/6aa687f98ae371b2f3bf7b8ff159009f5597f55d4f14e03805e8dfdea6c7/accessify-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "1ba0d7b163bcedfda04fed1b3223ee16", "sha256": "471905fd15e128c51e37b240804bb2e44f0be887ba105cacf90ef6725b26278a" }, "downloads": -1, "filename": "accessify-0.3.1.tar.gz", "has_sig": false, "md5_digest": "1ba0d7b163bcedfda04fed1b3223ee16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20736, "upload_time": "2019-03-26T22:33:22", "url": "https://files.pythonhosted.org/packages/f1/b9/7caef6d844143bf0383eb0513f5df212fe0bd5f50bd3b4a940043b868f35/accessify-0.3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "1ba0d7b163bcedfda04fed1b3223ee16", "sha256": "471905fd15e128c51e37b240804bb2e44f0be887ba105cacf90ef6725b26278a" }, "downloads": -1, "filename": "accessify-0.3.1.tar.gz", "has_sig": false, "md5_digest": "1ba0d7b163bcedfda04fed1b3223ee16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20736, "upload_time": "2019-03-26T22:33:22", "url": "https://files.pythonhosted.org/packages/f1/b9/7caef6d844143bf0383eb0513f5df212fe0bd5f50bd3b4a940043b868f35/accessify-0.3.1.tar.gz" } ] }