{ "info": { "author": "Tim Mitchell", "author_email": "tim.mitchell@seequent.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries" ], "description": "pure-interface\n==============\n\n.. image:: https://travis-ci.com/seequent/pure_interface.svg?branch=master\n :target: https://travis-ci.com/seequent/pure_interface\n\nA Python interface library that disallows function body content on interfaces and supports adaption.\n\nJump to the `Reference`_.\n\nFeatures\n--------\n* Prevents code in method bodies of an interface class\n* Ensures that method overrides have compatible signatures\n* Supports interface adaption.\n* Supports optional structural type checking for ``Interface.provided_by(a)`` and ``Interface.adapt(a)``\n* Allows concrete implementations the flexibility to implement abstract properties as instance attributes.\n* ``Interface.adapt()`` can return an implementation wrapper that provides *only* the\n attributes and methods defined by ``Interface``.\n* Warns if ``provided_by`` did a structural type check when inheritance would work.\n* Supports python 2.7 and 3.5+\n\nA note on the name\n------------------\nThe phrase *pure interface* applies only to the first design goal - a class that defines only an interface with no\nimplementation is a pure interface [*]_.\nIn every other respect the zen of 'practicality beats purity' applies.\n\nInstallation\n------------\npure_interface depends on the six_ and typing_ modules (typing is included in python 3.5 and later).\n\nYou can install released versions of ``pure_interface`` using pip::\n\n pip install pure-interface\n\nor you can grab the source code from GitHub_.\n\nDefining an Interface\n=====================\n\nFor simplicity in these examples we assume that the entire pure_interface namespace has been imported ::\n\n from pure_interface import *\n\nTo define an interface, simply inherit from the class ``PureInterface`` and write a PEP-544_ Protocol-like class\nleaving all method bodies empty::\n\n class IAnimal(PureInterface):\n height: float\n\n def speak(self, volume):\n pass\n\n\nLike Protocols, class annotations are considered part of the interface.\nIn Python versions earlier than 3.6 you can use the following alternate syntax::\n\n class IAnimal(PureInterface):\n height = None\n\n def speak(self, volume):\n pass\n\nThe value assigned to class attributes *must* be ``None`` and the attribute is removed from the class dictionary\n(since annotations are not in the class dictionary).\n\n``PureInterface`` is a subtype of ``abc.ABC`` and the ``abstractmethod`` and ``abstractproperty`` decorators work as expected.\nABC-style property definitions are also supported (and equivalent)::\n\n class IAnimal(PureInterface):\n @abstractproperty\n def height(self):\n pass\n\n @abstractmethod\n def speak(self, volume):\n pass\n\nAgain, the height property is removed from the class dictionary, but, as with the other syntaxes,\nall concrete subclasses will be required to have a ``height`` attribute.\n\nFor convenience the ``abc`` module abstract decorators are included in the ``pure_interface`` namespace, and\non Python 2.7 ``abstractclassmethod`` and ``abstractstaticmethod`` are also available.\nHowever these decorators are optional as **ALL** methods and properties on a ``PureInterface`` subclass are abstract.\nIn the examples above, both ``height`` and ``speak`` are considered abstract and must be overridden by subclasses.\n\nIncluding abstract decorators in your code can be useful for reminding yourself (and telling your IDE) that you need\nto override those methods. Another common way of informing an IDE that a method needs to be overridden is for\nthe method to raise ``NotImplementedError``. For this reason methods that just raise ``NotImplementedError`` are also\nconsidered empty.\n\nInterface classes cannot be instantiated ::\n\n IAnimal()\n InterfaceError: Interfaces cannot be instantiated.\n\nIncluding code in a method will result in an ``InterfaceError`` being raised when the module is imported. For example::\n\n class BadInterface(PureInterface):\n def method(self):\n print('hello')\n\n InterfaceError: Function \"method\" is not empty\n Did you forget to inherit from object to make the class concrete?\n\n\nThe ``dir()`` function will include all interface attributes so that ``mock.Mock(spec=IAnimal)`` will work as expected::\n\n >>> dir(IAnimal)\n ['__abstractmethods__', '__doc__', ..., 'height', 'speak']\n\n\n\nConcrete Implementations\n========================\n\nSimply inheriting from a pure interface and writing a concrete class will result in an ``InterfaceError`` exception\nas ``pure_interface`` will assume you are creating a sub-interface. To tell ``pure_interface`` that a type should be\nconcrete simply inherit from ``object`` as well (or anything else that isn't a ``PureInterface``). For example::\n\n class Animal(object, IAnimal):\n def __init__(self, height):\n self.height = height\n\n def speak(self, volume):\n print('hello')\n\n**Exception:** Mixing a ``PureInterface`` class with an ``abc.ABC`` interface class that only defines abstract methods\nand properties that satisfy the empty method criteria will result in a type that is considered a pure interface.::\n\n class ABCInterface(abc.ABC):\n @abstractmethod\n def foo(self):\n pass\n\n class MyPureInterface(ABCInterface, PureInterface):\n def bar(self):\n pass\n\nConcrete implementations may implement interface attributes in any way they like: as instance attributes, properties,\ncustom descriptors provided that they all exist at the end of ``__init__()``. Here is another valid implementation::\n\n class Animal2(object, IAnimal):\n def __init__(self, height):\n self._height = height\n\n @property\n def height(self):\n return self._height\n\n def speak(self, volume):\n print('hello')\n\nThe astute reader will notice that the ``Animal2`` bases list makes an inconsistent method resolution order.\nThis is handled by the ``PureInterfaceType`` meta-class by removing ``object`` from the front of the bases list.\nHowever static checkers such as mypy_ and some IDE's will complain. To get around this, ``pure_interface`` includes an empty\n``Concrete`` class which you can use to keep mypy and your IDE happy::\n\n class Concrete(object):\n pass\n\n class Animal2(Concrete, IAnimal):\n def __init__(self, height):\n self.height = height\n\n def speak(self, volume):\n print('hello')\n\nMethod Signatures\n-----------------\nMethod overrides are checked for compatibility with the interface.\nThis means that argument names must match exactly and that no new non-optional\narguments are present in the override. This enforces that calling the method\nwith interface parameters will aways work.\nFor example, given the interface method::\n\n def speak(self, volume):\n\nThen these overrides will all fail the checks and raise an ``InterfaceError``::\n\n def speak(self): # too few parameters\n def speak(self, loudness): # name does not match\n def speak(self, volume, language): # extra required argument\n\nHowever new optional parameters are permitted, as are ``*args`` and ``**kwargs``::\n\n def speak(self, volume, language='doggy speak')\n def speak(self, *args)\n\nImplementation Warnings\n-----------------------\n\nAs with ``abc.ABC``, the abstract method checking for a class is done when an object is instantiated.\nHowever it is useful to know about missing methods sooner than that. For this reason ``pure_interface`` will issue\na warning during module import when methods are missing from a concrete subclass. For example::\n\n class SilentAnimal(object, IAnimal):\n def __init__(self, height):\n self.height = height\n\nwill issue this warning::\n\n readme.py:28: UserWarning: Incomplete Implementation: SilentAnimal does not implement speak\n class SilentAnimal(object, IAnimal):\n\nTrying to create a ``SilentAnimal`` will fail in the standard abc way::\n\n SilentAnimal()\n InterfaceError: Can't instantiate abstract class SilentAnimal with abstract methods speak\n\nIf you have a mixin class that implements part of an interface you can suppress the warnings by adding an class attribute\ncalled ``pi_partial_implementation``. The value of the attribute is ignored, and the attribute itself is removed from\nthe class. For example::\n\n class HeightMixin(object, IAnimal):\n pi_partial_implementation = True\n\n def __init__(self, height):\n self.height = height\n\nwill not issue any warnings.\n\nThe warning messages are also appended to the module variable ``missing_method_warnings``, irrespective of any warning\nfilters (but only if ``is_development=True``). This provides an alternative to raising warnings as errors.\nWhen all your imports are complete you can check if this list is empty.::\n\n if pure_iterface.missing_method_warnings:\n for warning in pure_iterface.missing_method_warnings:\n print(warning)\n exit(1)\n\nNote that missing properties are NOT checked for as they may be provided by instance attributes.\n\nAdaption\n========\n\nRegistering Adapters\n--------------------\n\nAdapters for an interface are registered with the ``adapts`` decorator or with\nthe ``register_adapter`` function. Take for example an interface ``ISpeaker`` and a\nclass ``Talker`` and an adapter class ``TalkerToSpeaker``::\n\n class ISpeaker(PureInterface):\n def speak(self, volume):\n pass\n\n class Talker(object):\n def talk(self):\n return 'talk'\n\n @adapts(Talker)\n class TalkerToSpeaker(object, ISpeaker):\n def __init__(self, talker):\n self._talker = talker\n\n def speak(self, volume):\n return self._talker.talk()\n\nThe ``adapts`` decorator call above is equivalent to::\n\n register_adapter(TalkerToSpeaker, Talker, ISpeaker)\n\nThe ``ISpeaker`` parameter passed to ``register_adapter`` is the first interface in the MRO of the class being decorated (``TalkerToSpeaker``).\nIf there are no interface types in the MRO of the decorated class an ``InterfaceError`` exception is raised.\n\nAdapter factory functions can be decorated too, in which case the interface being adapted to needs to be specified::\n\n @adapts(Talker, ISpeaker)\n def talker_to_speaker(talker):\n return TalkerToSpeaker(talker)\n\nThe decorated adapter (whether class for function) must be callable with a single parameter - the object to adapt.\n\nAdapting Objects\n----------------\n\nThe ``PureInterface.adapt`` method will adapt an object to the given interface\nsuch that ``Interface.provided_by`` is ``True`` or raise ``AdaptionError`` if no adapter could be found. For example::\n\n speaker = ISpeaker.adapt(talker)\n isinstance(speaker, ISpeaker) --> True\n\nIf you want to get ``None`` rather than an exception then use::\n\n speaker = ISpeaker.adapt_or_none(talker)\n\nYou can filter a list of objects returning those objects that provide an interface\nusing ``filter_adapt(objects)``::\n\n list(ISpeaker.filter_adapt([None, Talker(), a_speaker, 'text']) --> [TalkerToSpeaker, a_speaker]\n\nTo adapt an object only if it is not ``None`` then use::\n\n ISpeaker.optional_adapt(optional_talker)\n\nThis is equivalent to::\n\n ISpeaker.adapt(optional_talker) if optional_talker is not None else None\n\nBy default the adaption functions will return an object which provides **only**\nthe functions and properties specified by the interface. For example given the\nfollowing implementation of the ``ISpeaker`` interface above::\n\n class TopicSpeaker(ISpeaker):\n def __init__(self, topic):\n self.topic = topic\n\n def speak(self, volume):\n return 'lets talk about {} very {}'.format(self.topic, volume)\n\n topic_speaker = TopicSpeaker('python')\n\nThen::\n\n speaker = ISpeaker.adapt(topic_speaker)\n speaker is topic_speaker --> False\n speaker.topic --> AttributeError(\"ISpeaker interface has no attribute topic\")\n\nThis is controlled by the optional ``interface_only`` parameter to ``adapt`` which defaults to ``True``.\nPass ``interface_only=False`` if you want the actual adapted object rather than a wrapper::\n\n speaker = ISpeaker.adapt(topic_speaker, interface_only=False)\n speaker is topic_speaker --> True\n speaker.topic --> 'Python'\n\nAccessing the ``topic`` attribute on an ``ISpeaker`` may work for all current implementations\nof ``ISpeaker``, but this code will likely break at some inconvenient time in the future.\n\nAdapters from sub-interfaces may be used to perform adaption if necessary. For example::\n\n class IA(PureInterface):\n foo = None\n\n class IB(IA):\n bar = None\n\n @adapts(int):\n class IntToB(object, IB):\n def __init__(self, x):\n self.foo = self.bar = x\n\nThen ``IA.adapt(4)`` will use the ``IntToB`` adapter to adapt ``4`` to ``IA`` (unless there is already an adapter\nfrom ``int`` to ``IA``)\n\nStructural Type Checking\n========================\n\nStructural_ type checking checks if an object has the attributes and methods defined by the interface.\n\n.. _Structural: https://en.wikipedia.org/wiki/Structural_type_system\n\nAs interfaces are inherited, you can usually use ``isinstance(obj, MyInterface)`` to check if an interface is provided.\nAn alternative to ``isinstance()`` is the ``PureInterface.provided_by(obj)`` classmethod which will fall back to structural type\nchecking if the instance is not an actual subclass. This can be controlled by the ``allow_implicit`` parameter which defaults to ``True``.\nThe structural type-checking does not check function signatures.::\n\n class Parrot(object):\n def __init__(self):\n self.height = 43\n\n def speak(self, volume):\n print('hello')\n\n p = Parrot()\n isinstance(p, IAnimal) --> False\n IAnimal.provided_by(p) --> True\n IAnimal.provided_by(p, allow_implicit=False) --> False\n\nThe structural type checking makes working with data transfer objects (DTO's) much easier.::\n\n class IMyDataType(PureInterface):\n thing: str\n\n class DTO(object):\n pass\n\n d = DTO()\n d.thing = 'hello'\n IMyDataType.provided_by(d) --> True\n e = DTO()\n e.something_else = True\n IMyDataType.provided_by(e) --> False\n\nAdaption also supports structural typing by passing ``allow_implicit=True`` (but this is not the default)::\n\n speaker = ISpeaker.adapt(Parrot(), allow_implicit=True)\n ISpeaker.provided_by(speaker) --> True\n\nWhen using ``provided_by()`` or ``adapt()`` with ``allow_implicit=True``, a warning may be issued informing you that\nthe structurally typed object should inherit the interface. The warning is only issued if the interface is implemented by the\nclass (and not by instance attributes as in the DTO case above) and the warning is only issued once for each\nclass, interface pair. For example::\n\n s = ISpeaker.adapt(Parrot())\n UserWarning: Class Parrot implements ISpeaker.\n Consider inheriting ISpeaker or using ISpeaker.register(Parrot)\n\nDataclass Support\n=================\ndataclasses_ were added in Python 3.7. When used in this and later versions of Python, ``pure_interface`` provides a\n``dataclass`` decorator. This decorator can be used to create a dataclass that implements an interface. For example::\n\n class IAnimal2(PureInterface):\n height: float\n species: str\n\n def speak(self):\n pass\n\n @dataclass\n class Animal(Concrete, IAnimal2):\n def speak(self):\n print('hello, I am {}m tall {}', self.height, self.species)\n\n a = Animal(height=4.5, species='Giraffe')\n\nThe builtin Python ``dataclass`` decorator cannot be used because it will not create attributes for the\n``height`` and ``species`` annotations on the interface base class ``IAnimal2``.\nAs per the built-in ``dataclass`` decorator, only interface attributes defined\nusing annotation syntax are supported (and not the alternatives syntaxes provided by ``pure_interface``).\n\nInterface Type Information\n==========================\nThe ``pure_interface`` module provides these functions for returning information about interface types.\n\ntype_is_pure_interface(cls)\n Return True if cls is a pure interface, False otherwise or if cls is not a class.\n\nget_type_interfaces(cls)\n Returns all interfaces in the cls mro including cls itself if it is an interface\n\nget_interface_names(cls)\n Returns a ``frozenset`` of names (methods and attributes) defined by the interface.\n if interface is not a ``PureInterface`` subtype then an empty set is returned.\n\nget_interface_method_names(interface)\n Returns a ``frozenset`` of names of methods defined by the interface.\n if interface is not a ``PureInterface`` subtype then an empty set is returned\n\nget_interface_attribute_names(interface)\n Returns a ``frozenset`` of names of attributes defined by the interface.\n if interface is not a ``PureInterface`` subtype then an empty set is returned\n\n\nAutomatic Adaption\n==================\nThe function decorator ``adapt_args`` adapts arguments to a decorated function to the types given.\nFor example::\n\n @adapt_args(foo=IFoo, bar=IBar)\n def my_func(foo, bar=None):\n pass\n\nIn Python 3.5 and later the types can be taken from the argument annotations.::\n\n @adapt_args\n def my_func(foo: IFoo, bar: IBar=None):\n pass\n\nThis would adapt the ``foo`` parameter to ``IFoo`` (with ``IFoo.optional_adapt(foo))`` and ``bar`` to ``IBar\n(using ``IBar.optional_adapt(bar)``)\nbefore passing them to my_func. ``None`` values are never adapted, so ``my_func(foo, None)`` will work, otherwise\n``AdaptionError`` is raised if the parameter is not adaptable.\nAll arguments must be specified as keyword arguments::\n\n @adapt_args(IFoo, IBar) # NOT ALLOWED\n def other_func(foo, bar):\n pass\n\nDevelopment Flag\n================\n\nMuch of the empty function and other checking is awesome whilst writing your code but\nultimately slows down production code.\nFor this reason the ``pure_interface`` module has an ``is_development`` switch.::\n\n is_development = not hasattr(sys, 'frozen')\n\n``is_development`` defaults to ``True`` if running from source and default to ``False`` if bundled into an executable by\npy2exe_, cx_Freeze_ or similar tools.\n\nIf you manually change this flag it must be set before modules using the ``PureInterface`` type\nare imported or else the change will not have any effect.\n\nIf ``is_development`` if ``False`` then:\n\n * Signatures of overriding methods are not checked\n * No warnings are issued by the adaption functions\n * No incomplete implementation warnings are issued\n * The default value of ``interface_only`` is set to ``False``, so that interface wrappers are not created.\n\n\nPyContracts Integration\n=======================\n\nYou can use ``pure_interface`` with PyContracts_\n\n.. _PyContracts: https://pypi.python.org/pypi/PyContracts\n\nSimply import the ``pure_contracts`` module and use the ``ContractInterface`` class defined there as you\nwould the ``PureInterface`` class described above.\nFor example::\n\n from pure_contracts import ContractInterface\n from contracts import contract\n\n class ISpeaker(ContractInterface):\n @contract(volume=int, returns=unicode)\n def speak(self, volume):\n pass\n\n\nReference\n=========\nClasses\n-------\n\n**PureInterfaceType(abc.ABCMeta)**\n Metaclass for checking interface and implementation classes.\n Adding PureInterfaceType as a meta-class to a class will not make that class an interface, you need to\n inherit from ``PureInterface`` class to define an interface.\n\n In addition to the ``register`` method provided by ``ABCMeta``, the following functions are defined on\n ``PureInterfaceType`` and can be accessed directly when the ``PureInterface`` methods are overridden\n for other purposes.\n\n **adapt** *(cls, obj, allow_implicit=False, interface_only=None)*\n See ``PureInterface.adapt`` for a description.\n\n **adapt_or_none** *(cls, obj, allow_implicit=False, interface_only=None)*\n See ``PureInterface.adapt_or_none`` for a description\n\n **optional_adapt** *(cls, obj, allow_implicit=False, interface_only=None)*\n See ``PureInterface.optional_adapt`` for a description\n\n **can_adapt** *(cls, obj, allow_implicit=False)*\n See ``PureInterface.can_adapt`` for a description\n\n **filter_adapt** *(cls, objects, allow_implicit=False, interface_only=None)*\n See ``PureInterface.filter_adapt`` for a description\n\n **interface_only** *(cls, implementation)*\n See ``PureInterface.interface_only`` for a description\n\n **provided_by** *(cls, obj, allow_implicit=True)*\n See ``PureInterface.provided_by`` for a description\n\n Classes created with a metaclass of ``PureInterfaceType`` will have the following property:\n\n **_pi** Information about the class that is used by this meta-class. This attribute is reserved for use by\n ``pure_interface`` and must not be overridden.\n\n\n**PureInterface**\n Base class for defining interfaces. The following methods are provided:\n\n **adapt** *(obj, allow_implicit=False, interface_only=None)*\n Adapts ``obj`` to this interface. If ``allow_implicit`` is ``True`` permit structural adaptions.\n If ``interface_only`` is ``None`` the it is set to the value of ``is_development``.\n If ``interface_only`` resolves to ``True`` a wrapper object that provides\n the properties and methods defined by the interface and nothing else is returned.\n Raises ``AdaptionError`` if no adaption is possible or a registered adapter returns an object not providing\n this interface.\n\n **adapt_or_none** *(obj, allow_implicit=False, interface_only=None)*\n As per **adapt()** except returns ``None`` instead of raising a ``AdaptionError``\n\n **optional_adapt** *(obj, allow_implicit=False, interface_only=None)*\n Adapts obj to this interface if it is not ``None`` returning ``None`` otherwise.\n Short-cut for ``adapt(obj) if obj is not None else None``\n\n **can_adapt** *(obj, allow_implicit=False)*\n Returns ``True`` if ``adapt(obj, allow_implicit)`` will succeed. Short-cut for\n ``adapt_or_none(obj) is not None``\n\n **filter_adapt** *(objects, allow_implicit=False, interface_only=None)*\n Generates adaptions of each item in *objects* that provide this interface.\n *allow_implicit* and *interface_only* are as for **adapt**.\n Objects that cannot be adapted to this interface are silently skipped.\n\n **interface_only** *(implementation)*\n Returns a wrapper around *implementation* that provides the properties and methods defined by\n the interface and nothing else.\n\n **provided_by** *(obj, allow_implicit=True)*\n Returns ``True`` if *obj* provides this interface. If ``allow_implicit`` is ``True`` the also\n return ``True`` for objects that provide the interface structure but do not inherit from it.\n Raises ``InterfaceError`` if the class is a concrete type.\n\n\n**Concrete**\n Empty class to create a consistent MRO in implementation classes.\n\n\nFunctions\n---------\n**adapts** *(from_type, to_interface=None)*\n Class or function decorator for declaring an adapter from *from_type* to *to_interface*.\n The class or function being decorated must take a single argument (an instance of *from_type*) and\n provide (or return and object providing) *to_interface*. The adapter may return an object that provides\n the interface structurally only, however ``adapt`` must be called with ``allow_implicit=True`` for this to work.\n If decorating a class, *to_interface* may be ``None`` to use the first interface in the class's MRO.\n\n**register_adapter** *(adapter, from_type, to_interface)*\n Registers an adapter to convert instances of *from_type* to objects that provide *to_interface*\n for the *to_interface.adapt()* method. *adapter* must be a callable that takes a single argument\n (an instance of *from_type*) and returns and object providing *to_interface*.\n\n**type_is_pure_interface** *(cls)*\n Return ``True`` if *cls* is a pure interface and ``False`` otherwise\n\n**get_type_interfaces** *(cls)*\n Returns all interfaces in the *cls* mro including cls itself if it is an interface\n\n**get_interface_names** *(cls)*\n Returns a ``frozenset`` of names (methods and attributes) defined by the interface.\n if interface is not a ``PureInterface`` subtype then an empty set is returned.\n\n**get_interface_method_names** *(cls)*\n Returns a ``frozenset`` of names of methods defined by the interface.\n If *cls* is not a ``PureInterface`` subtype then an empty set is returned.\n\n**get_interface_attribute_names** *(cls)*\n Returns a ``frozenset`` of names of class attributes and annotations defined by the interface\n If *cls* is not a ``PureInterface`` subtype then an empty set is returned.\n\n**dataclass** *(_cls=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)*\n This function is a re-implementation of the standard Python ``dataclasses.dataclass`` decorator.\n In addition to the fields on the decorated class, all annotations on interface base classes are added as fields.\n See the Python dataclasses_ documentation for more details.\n\n 3.7+ Only\n\n\nExceptions\n----------\n**PureInterfaceError**\n Base exception class for all exceptions raised by ``pure_interface``.\n\n**InterfaceError**\n Exception raised for problems with interfaces\n\n**AdaptionError**\n Exception raised for problems with adapters or adapting.\n\n\nModule Attributes\n-----------------\n**is_development**\n Set to ``True`` to enable all checks and warnings.\n If set to ``False`` then:\n\n * Signatures of overriding methods are not checked\n * No warnings are issued by the adaption functions\n * No incomplete implementation warnings are issued\n * The default value of ``interface_only`` is set to ``False``, so that interface wrappers are not created.\n\n\n**missing_method_warnings**\n The list of warning messages for concrete classes with missing interface (abstract) method overrides.\n Note that missing properties are NOT checked for as they may be provided by instance attributes.\n\n-----------\n\n.. _six: https://pypi.python.org/pypi/six\n.. _typing: https://pypi.python.org/pypi/typing\n.. _PEP-544: https://www.python.org/dev/peps/pep-0544/\n.. _GitHub: https://github.com/seequent/pure_interface\n.. _mypy: http://mypy-lang.org/\n.. _py2exe: https://pypi.python.org/pypi/py2exe\n.. _cx_Freeze: https://pypi.python.org/pypi/cx_Freeze\n.. _dataclasses: https://docs.python.org/3/library/dataclasses.html\n.. [*] We don't talk about the methods on the base ``PureInterface`` class. In earlier versions they\n were all on the meta class but then practicality got in the way.\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/seequent/pure_interface", "keywords": "abc interface adapt adaption mapper structural typing", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "pure-interface", "package_url": "https://pypi.org/project/pure-interface/", "platform": "", "project_url": "https://pypi.org/project/pure-interface/", "project_urls": { "Homepage": "https://github.com/seequent/pure_interface" }, "release_url": "https://pypi.org/project/pure-interface/3.5.2/", "requires_dist": null, "requires_python": "", "summary": "A Python interface library that disallows function body content on interfaces and supports adaption.", "version": "3.5.2" }, "last_serial": 5621517, "releases": { "1.7.0": [ { "comment_text": "", "digests": { "md5": "2a459e4940393ddd10d580bc90d0baba", "sha256": "43a29aeb39d671578af36c1d382552ec3ecaaf1837f7b96de4f7ffac50e19cdd" }, "downloads": -1, "filename": "pure_interface-1.7.0.tar.gz", "has_sig": false, "md5_digest": "2a459e4940393ddd10d580bc90d0baba", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13499, "upload_time": "2017-08-09T03:07:40", "url": "https://files.pythonhosted.org/packages/2d/b9/ae41e7db84a622bb91c69e978a4f4f8f4af0013e74766a93bed4d902c4c7/pure_interface-1.7.0.tar.gz" } ], "1.7.1": [ { "comment_text": "", "digests": { "md5": "707f28f83f738e47032a791538a076e9", "sha256": "b5082f9a0407f785892bd42972c8d64d7553cf937e091f7a4598b3d25875fe1b" }, "downloads": -1, "filename": "pure_interface-1.7.1.tar.gz", "has_sig": false, "md5_digest": "707f28f83f738e47032a791538a076e9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13512, "upload_time": "2017-09-21T02:45:19", "url": "https://files.pythonhosted.org/packages/79/4c/56eaeb36b7103f25642e7631e38deb307406fa82d2315b6c8b84160928d2/pure_interface-1.7.1.tar.gz" } ], "1.7.2": [ { "comment_text": "", "digests": { "md5": "6409f043d7222f1823166eefb38c6b16", "sha256": "9057822f60067d8f9e48b51cd87497f4836640d13d5e6be8fb4f2eec0f16d482" }, "downloads": -1, "filename": "pure_interface-1.7.2.tar.gz", "has_sig": false, "md5_digest": "6409f043d7222f1823166eefb38c6b16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13563, "upload_time": "2017-09-21T03:28:27", "url": "https://files.pythonhosted.org/packages/bf/85/216b571acd2d2cd06e71a43f86668dd7e854b55645cc6654e14531fd588d/pure_interface-1.7.2.tar.gz" } ], "1.7.3": [ { "comment_text": "", "digests": { "md5": "6db139b51956c71dd4d500e23585dc92", "sha256": "69d123d4c0fa625570469d929fbc027a36abac9b206b968ac4ef24230864f944" }, "downloads": -1, "filename": "pure_interface-1.7.3.tar.gz", "has_sig": false, "md5_digest": "6db139b51956c71dd4d500e23585dc92", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13588, "upload_time": "2017-09-26T04:36:11", "url": "https://files.pythonhosted.org/packages/95/5d/53dcbfddd7913e47e382395f7ea5edaceb101d693eff3b06adfb936d945b/pure_interface-1.7.3.tar.gz" } ], "1.7.4": [ { "comment_text": "", "digests": { "md5": "88e690c98390ee3a48e7a8d34b292a34", "sha256": "62e052ffeee16b218b907189f1ef26f228c44cbc3ae93c11b08e7d8cb3fdddcd" }, "downloads": -1, "filename": "pure_interface-1.7.4.tar.gz", "has_sig": false, "md5_digest": "88e690c98390ee3a48e7a8d34b292a34", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13634, "upload_time": "2017-09-26T22:57:49", "url": "https://files.pythonhosted.org/packages/07/32/3f87992373556b16af188bbe0c67c795d1dd3b1bfc71e57643eedf0215fb/pure_interface-1.7.4.tar.gz" } ], "1.8.0": [ { "comment_text": "", "digests": { "md5": "995be06b49a6952a97167b1e68cec926", "sha256": "2d6658f6a49cd74b9c09830cefbb604e7fbb8aebb0c5b4ca14165acb3371d762" }, "downloads": -1, "filename": "pure_interface-1.8.0.tar.gz", "has_sig": false, "md5_digest": "995be06b49a6952a97167b1e68cec926", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15133, "upload_time": "2017-10-12T20:21:40", "url": "https://files.pythonhosted.org/packages/00/61/81deb150f71387ff3da82a5191e5ed526243830e2230855699498f9f634e/pure_interface-1.8.0.tar.gz" } ], "1.9.2": [ { "comment_text": "", "digests": { "md5": "2dcadd16af9025cbad1c74dfb5f35994", "sha256": "a89af1a44f1bec1b30d45c36adfc340df36036e0ff8d2b7b1b13294cae64bba8" }, "downloads": -1, "filename": "pure_interface-1.9.2.tar.gz", "has_sig": false, "md5_digest": "2dcadd16af9025cbad1c74dfb5f35994", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15351, "upload_time": "2017-11-10T02:21:26", "url": "https://files.pythonhosted.org/packages/14/12/77010b6e41a25092aacb39ccd43727c2af535aa7b5373b68fe6153186dca/pure_interface-1.9.2.tar.gz" } ], "1.9.3": [ { "comment_text": "", "digests": { "md5": "4ce34f01af948464ea4bda122a86b732", "sha256": "9b17e8f55986adfa34263df55eab409c53b9f16d1a31b22bd3fad9b478348ed9" }, "downloads": -1, "filename": "pure_interface-1.9.3.tar.gz", "has_sig": false, "md5_digest": "4ce34f01af948464ea4bda122a86b732", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15799, "upload_time": "2017-11-21T22:53:15", "url": "https://files.pythonhosted.org/packages/7a/5a/92dff1bdf402d07e8966d03fc88c47a0bf5e8b2ec2c34a166edc5da4fe65/pure_interface-1.9.3.tar.gz" } ], "1.9.4": [ { "comment_text": "", "digests": { "md5": "73093ffd2dee5d3fffdb3c390adec881", "sha256": "34e0906f10097c793e5fc3b3c9daddf8860b9f75d154caa31a004171826a662a" }, "downloads": -1, "filename": "pure_interface-1.9.4.tar.gz", "has_sig": false, "md5_digest": "73093ffd2dee5d3fffdb3c390adec881", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15850, "upload_time": "2017-11-21T23:10:31", "url": "https://files.pythonhosted.org/packages/90/af/1a97564e054609e51d7ad02febd22e3fa55280f150aeaaaece2e044e2d69/pure_interface-1.9.4.tar.gz" } ], "1.9.5": [ { "comment_text": "", "digests": { "md5": "04679baa907fdc6960f1d5fec560e5a7", "sha256": "b680b0aa6a7223501019ddaf983171057597ec86d6d25c4d510489f507c06651" }, "downloads": -1, "filename": "pure_interface-1.9.5.tar.gz", "has_sig": false, "md5_digest": "04679baa907fdc6960f1d5fec560e5a7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16346, "upload_time": "2017-11-21T23:54:56", "url": "https://files.pythonhosted.org/packages/b5/ed/cab5d5f72b0bc8810f8e10572c48272e195a109cb112b4075d10a83dddb2/pure_interface-1.9.5.tar.gz" } ], "1.9.6": [ { "comment_text": "", "digests": { "md5": "e160ff27ca9e497b600aa62070b43ab2", "sha256": "ea51b493a13380aa805af9d0d01b5b97f920eed8d6ddeca2c4964ebc17e7a51d" }, "downloads": -1, "filename": "pure_interface-1.9.6.tar.gz", "has_sig": false, "md5_digest": "e160ff27ca9e497b600aa62070b43ab2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16342, "upload_time": "2017-12-07T20:23:54", "url": "https://files.pythonhosted.org/packages/6b/9b/7cafad9e1b96180261c7f1d21d4c9f44fae1bd2280b243996be991b78138/pure_interface-1.9.6.tar.gz" } ], "1.9.7": [ { "comment_text": "", "digests": { "md5": "2f96924044ca5f9162895ed799c120e2", "sha256": "51c72a177489c5dea104b12f3eeaa89eca737b29247d802826b2ff3f71ea41a3" }, "downloads": -1, "filename": "pure_interface-1.9.7.tar.gz", "has_sig": false, "md5_digest": "2f96924044ca5f9162895ed799c120e2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16527, "upload_time": "2018-01-30T02:40:57", "url": "https://files.pythonhosted.org/packages/db/f0/f90b78e44de52b719bc9bfbc86e2e00b12319ab8db13fb41c67bc07cd5e9/pure_interface-1.9.7.tar.gz" } ], "1.9.8": [ { "comment_text": "", "digests": { "md5": "02c157c5e070da1758bc7fcf9976e67d", "sha256": "6f18a3f8b4e7b2d77b01c3546f6e5dfc4b618ffae3867617b8521739f70b1c71" }, "downloads": -1, "filename": "pure_interface-1.9.8.tar.gz", "has_sig": false, "md5_digest": "02c157c5e070da1758bc7fcf9976e67d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16535, "upload_time": "2018-02-08T20:50:16", "url": "https://files.pythonhosted.org/packages/11/25/c292d93e1eb1fa03c9e062678180df289d8bf18b185afd0b4bab4f162592/pure_interface-1.9.8.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "1ae51c52bd8c6e972a375f46a44a2b70", "sha256": "9286f4ff72761d17a9fbae4e03d2f7ead3e1f68a17c9b26f15b76f3018ed2e81" }, "downloads": -1, "filename": "pure_interface-2.0.0.tar.gz", "has_sig": false, "md5_digest": "1ae51c52bd8c6e972a375f46a44a2b70", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17632, "upload_time": "2018-02-21T00:37:10", "url": "https://files.pythonhosted.org/packages/de/10/2e8e2ca7dd3bcf29f0384b193f7c60c9ec8c0283d78a8d515edecf5cb827/pure_interface-2.0.0.tar.gz" } ], "2.1.0": [ { "comment_text": "", "digests": { "md5": "d1abce49132604de019be4d788b60f54", "sha256": "aa0187ca20cac8d107e44c3abe044ba44c372209d6e12e8e801fa12af6ed0a8c" }, "downloads": -1, "filename": "pure_interface-2.1.0.tar.gz", "has_sig": false, "md5_digest": "d1abce49132604de019be4d788b60f54", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18053, "upload_time": "2018-03-08T00:26:12", "url": "https://files.pythonhosted.org/packages/be/d2/31ff5e754fbe5dd5bc3750cc203b63e873eb9024d0adbb039ee8314daca5/pure_interface-2.1.0.tar.gz" } ], "2.2.0": [ { "comment_text": "", "digests": { "md5": "c9ab8a3d304d06ed72506f268563fe01", "sha256": "e01a88e71d1d49710ec2e48dcc03e6d6e9127e80f0c60c50be334faaa42fb103" }, "downloads": -1, "filename": "pure_interface-2.2.0.tar.gz", "has_sig": false, "md5_digest": "c9ab8a3d304d06ed72506f268563fe01", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18091, "upload_time": "2018-03-08T01:32:58", "url": "https://files.pythonhosted.org/packages/f9/9c/cbfe43fa0a9b918547cced08b7fed63b45af6c6ab6221444f3eb90201f74/pure_interface-2.2.0.tar.gz" } ], "2.2.1": [ { "comment_text": "", "digests": { "md5": "6def5e30c09788db6470c294d935ccd4", "sha256": "ee5176c468faed8bfc4b391ca232557c50fe2ffb4340e233b551038f616a29f6" }, "downloads": -1, "filename": "pure_interface-2.2.1.tar.gz", "has_sig": false, "md5_digest": "6def5e30c09788db6470c294d935ccd4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18521, "upload_time": "2018-03-08T22:50:52", "url": "https://files.pythonhosted.org/packages/9e/e7/c3009f951a7ed55e1e5306601938fce814b873ad828469092d78563b9d59/pure_interface-2.2.1.tar.gz" } ], "3.0.0": [ { "comment_text": "", "digests": { "md5": "fe3cbb3fe6910d442cdce3e58dead018", "sha256": "631d41fa042aeeea43b5b7d4fe2c9aacc79076fdd5eec95f7319a630224f1afc" }, "downloads": -1, "filename": "pure_interface-3.0.0.tar.gz", "has_sig": false, "md5_digest": "fe3cbb3fe6910d442cdce3e58dead018", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21488, "upload_time": "2018-03-22T21:55:48", "url": "https://files.pythonhosted.org/packages/f7/b3/a6eedd173be68d929b6bb1e6c903b7d7b7c9de9c8958fa2891ca1c16ca9d/pure_interface-3.0.0.tar.gz" } ], "3.0.3": [ { "comment_text": "", "digests": { "md5": "8eaea8e86ff1fc63a0bbf874fb151256", "sha256": "d16ca9d3e1e1a421a2353e9cc9cc3df8db538e2d5016c45d13fb42cf680ad33d" }, "downloads": -1, "filename": "pure_interface-3.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8eaea8e86ff1fc63a0bbf874fb151256", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 23946, "upload_time": "2018-06-28T00:08:00", "url": "https://files.pythonhosted.org/packages/92/c0/77e0d89ba5632aec467d9597e1901060a2726069ec0011ea58657684c289/pure_interface-3.0.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9b399d13cb1676bc5f86b3f04bbee393", "sha256": "ec48f779136215ead7f46b157bc55675909553043953d7d5fcbd8776fdea3d72" }, "downloads": -1, "filename": "pure_interface-3.0.3.tar.gz", "has_sig": false, "md5_digest": "9b399d13cb1676bc5f86b3f04bbee393", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22154, "upload_time": "2018-06-27T23:49:15", "url": "https://files.pythonhosted.org/packages/06/d3/9a8117ba1beffd41a13f31f80d5d6034bd1ff831bd4ed5fae8f9c3ada493/pure_interface-3.0.3.tar.gz" } ], "3.0.4": [ { "comment_text": "", "digests": { "md5": "a39ddb133da07df1f460a9c08dc08f14", "sha256": "ea3018d6bedd7619a22afd8bd148dc17e23077c171a3470a1b06818a5812e4aa" }, "downloads": -1, "filename": "pure_interface-3.0.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a39ddb133da07df1f460a9c08dc08f14", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24057, "upload_time": "2018-07-02T22:33:26", "url": "https://files.pythonhosted.org/packages/f2/a7/cb4f66656fbfe7c3b7f3a8b4705bd2a4172649f753700570852787f5e2c9/pure_interface-3.0.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8e5a50b98ea1f2d179865b3d03a9eb24", "sha256": "9690a23a643414773e7bbf0430525d0bdd48517d8796ec09769998be990f9b9a" }, "downloads": -1, "filename": "pure_interface-3.0.4.tar.gz", "has_sig": false, "md5_digest": "8e5a50b98ea1f2d179865b3d03a9eb24", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22239, "upload_time": "2018-07-02T22:33:29", "url": "https://files.pythonhosted.org/packages/99/a5/89b45482f60983c8dd5a034ef0f8dfd7be2d513df8a12bcef634f9acd340/pure_interface-3.0.4.tar.gz" } ], "3.1.0": [ { "comment_text": "", "digests": { "md5": "e4ceea932ff1312055d9e5cd9da56802", "sha256": "2899cd4d693fb77e5d82488ace3b14ba577fb282ac213f3d010479b59e5e45c4" }, "downloads": -1, "filename": "pure_interface-3.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e4ceea932ff1312055d9e5cd9da56802", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24415, "upload_time": "2018-08-27T04:25:04", "url": "https://files.pythonhosted.org/packages/0d/ec/cd9ebbb195dca2bc6b3331fdfe4ca135d788f2fad57d7e307b3205e6a69f/pure_interface-3.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ea49ace4bfb22435be4ea384b2c2e5c9", "sha256": "c2a443beac0e0265a9795c124554ea87bc5265fcdfe4e0371e7ed739203865cd" }, "downloads": -1, "filename": "pure_interface-3.1.0.tar.gz", "has_sig": false, "md5_digest": "ea49ace4bfb22435be4ea384b2c2e5c9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28185, "upload_time": "2018-08-27T04:25:06", "url": "https://files.pythonhosted.org/packages/32/2c/0574fbf55505fb0df97021a7157aff1864f861e92f53478d685ba0ef3550/pure_interface-3.1.0.tar.gz" } ], "3.1.1": [ { "comment_text": "", "digests": { "md5": "d93baf6896f60fc81e8aaad7d69e1cd2", "sha256": "44c7a60384797b7eeb2ca0fdf994d0cd70e3aba8276837816b3034565055a97d" }, "downloads": -1, "filename": "pure_interface-3.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "d93baf6896f60fc81e8aaad7d69e1cd2", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24489, "upload_time": "2018-08-27T21:06:27", "url": "https://files.pythonhosted.org/packages/b0/f9/8a509d30b5e179ff667204a451253abe3fcd7a3e14110cc939bba8ab60b1/pure_interface-3.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b6fbe945c95c30946ff6e24ce559d075", "sha256": "08ba7426f67f15dffd10df0796c0e5e939cbe05eb10622a7d3cca3d1e1e55d5d" }, "downloads": -1, "filename": "pure_interface-3.1.1.tar.gz", "has_sig": false, "md5_digest": "b6fbe945c95c30946ff6e24ce559d075", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28269, "upload_time": "2018-08-27T21:06:29", "url": "https://files.pythonhosted.org/packages/d3/b0/a33914b5ee12b7a96d67dfdac56e4956fd3624cc9a0a1d6f7ff3a9161d23/pure_interface-3.1.1.tar.gz" } ], "3.2.0": [ { "comment_text": "", "digests": { "md5": "51704a30a9188be48d0ad6864078c7aa", "sha256": "ab82e83f6194f079bd722af0a824bb61861e34f636b16b20269cf3bc0ee3bf38" }, "downloads": -1, "filename": "pure_interface-3.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "51704a30a9188be48d0ad6864078c7aa", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24164, "upload_time": "2018-10-16T22:55:11", "url": "https://files.pythonhosted.org/packages/99/a3/add252398337bcc0c93954cde3e6048d8bce60b7fb87ab72e7675451ff30/pure_interface-3.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "34e31c0349dce285412bc2c13d64a3fa", "sha256": "5dbdb61c983e20b07a08db5ef3c4e1b1c3d575f61fb30edff3f6248eb7ad579f" }, "downloads": -1, "filename": "pure_interface-3.2.0.tar.gz", "has_sig": false, "md5_digest": "34e31c0349dce285412bc2c13d64a3fa", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22353, "upload_time": "2018-10-16T22:55:13", "url": "https://files.pythonhosted.org/packages/b0/c6/67058af2f198c7458c70566c6993b312c23a84ec85f6365f2de63b2d785e/pure_interface-3.2.0.tar.gz" } ], "3.3.0": [ { "comment_text": "", "digests": { "md5": "39d8f0910fd2539813c5986713dfccf4", "sha256": "c97fb10326c837a65666f27f141cc7abc96938a3f4ea14d72629ba18364a3852" }, "downloads": -1, "filename": "pure_interface-3.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "39d8f0910fd2539813c5986713dfccf4", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24182, "upload_time": "2018-10-19T00:20:47", "url": "https://files.pythonhosted.org/packages/fa/f9/69abbd5e1498b72e6f77a440196cda1c81a9a1b2f29a87b27bc4af877731/pure_interface-3.3.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b58d28dda36374266d6e168c56313c13", "sha256": "f75820c21e508553ee267cf2873bfc67bb7d0b4bfbabbc8bbc4d00aaf7af4707" }, "downloads": -1, "filename": "pure_interface-3.3.0.tar.gz", "has_sig": false, "md5_digest": "b58d28dda36374266d6e168c56313c13", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22362, "upload_time": "2018-10-19T00:20:48", "url": "https://files.pythonhosted.org/packages/bf/4e/d067cc4fdf93de95930b5963ec80aab60ee76293b9ecdcf56b3292673207/pure_interface-3.3.0.tar.gz" } ], "3.3.1": [ { "comment_text": "", "digests": { "md5": "5621faca19a16cefaafa6656e5cc61b3", "sha256": "dd81854181e31e964edba09f348440a4e77ae84af634dcd471d24876d1a82614" }, "downloads": -1, "filename": "pure_interface-3.3.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "5621faca19a16cefaafa6656e5cc61b3", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 24782, "upload_time": "2018-10-23T01:09:59", "url": "https://files.pythonhosted.org/packages/0d/74/09a92888e41206373574f92c5235fb659894f2ff07e028b0464da64ecb92/pure_interface-3.3.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6f1a6bfea4baf1fb310aa3a7aaee2020", "sha256": "7e875b796455dfaaf1bd03f496539524fcc1d267dedcff49260b10bc8ad7842d" }, "downloads": -1, "filename": "pure_interface-3.3.1.tar.gz", "has_sig": false, "md5_digest": "6f1a6bfea4baf1fb310aa3a7aaee2020", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28965, "upload_time": "2018-10-23T01:10:01", "url": "https://files.pythonhosted.org/packages/d9/0a/47bb1c4ef1e36a063ec82177b41231c261bcc47012393465b7e9bb85b7c4/pure_interface-3.3.1.tar.gz" } ], "3.3.2": [ { "comment_text": "", "digests": { "md5": "3f0a6822425abb3976a935203e9a66c8", "sha256": "67d6e5a47d81d72fa7bed59bf1c354e2ba391a647316cc8e6774234d9200f42a" }, "downloads": -1, "filename": "pure_interface-3.3.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "3f0a6822425abb3976a935203e9a66c8", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 16918, "upload_time": "2019-08-02T01:39:56", "url": "https://files.pythonhosted.org/packages/d0/12/c2bff5b26ef15a2f374d1269d3692147345f0c04ca23cefd7b276c7c04a1/pure_interface-3.3.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "88f156055ab23f39a3403af4703e3f21", "sha256": "8630218f16836e5c93fc9089805a94971dd00c56a67aadb391a7d79cbdac6af9" }, "downloads": -1, "filename": "pure_interface-3.3.2.tar.gz", "has_sig": false, "md5_digest": "88f156055ab23f39a3403af4703e3f21", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29000, "upload_time": "2019-08-01T22:52:03", "url": "https://files.pythonhosted.org/packages/ca/a6/589410951d4eda5bdcbcc51d1f2bc8fda44b7f365e4ba4d4bfd3a7cb74fe/pure_interface-3.3.2.tar.gz" } ], "3.4.0": [ { "comment_text": "", "digests": { "md5": "a8948edb92e1fec9221211c1fe4977d5", "sha256": "6f48062073f711b6cf4034bf1e7581fcc268c69bab24563d9b775d15da3c0f7e" }, "downloads": -1, "filename": "pure_interface-3.4.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a8948edb92e1fec9221211c1fe4977d5", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18689, "upload_time": "2019-04-12T02:39:01", "url": "https://files.pythonhosted.org/packages/18/24/89c02affa762e10d6062674a5a3eeb42ba1bec3eedcc065ca314a43d7251/pure_interface-3.4.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a11e51972839b1c04a11f738f4944941", "sha256": "77ef5a16e6c8225cf5ebdc8dfce7a5c0c02d5968490dbd686b1f26fa3361e334" }, "downloads": -1, "filename": "pure_interface-3.4.0.tar.gz", "has_sig": false, "md5_digest": "a11e51972839b1c04a11f738f4944941", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31609, "upload_time": "2019-04-12T02:39:05", "url": "https://files.pythonhosted.org/packages/98/19/01a34e8e253bdefef984a4ed1234f7ee1059d0d62bc7b35179c8be204478/pure_interface-3.4.0.tar.gz" } ], "3.4.1": [ { "comment_text": "", "digests": { "md5": "d4ca00571a648c9d02b231036a6a5194", "sha256": "c760b5552496a9b41642b9f44ea9e793d3c6d8f04c411d062e3fcb87ac5b3a78" }, "downloads": -1, "filename": "pure_interface-3.4.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "d4ca00571a648c9d02b231036a6a5194", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 18691, "upload_time": "2019-04-23T03:17:07", "url": "https://files.pythonhosted.org/packages/80/83/c9bb540c05970d43c9d8a6fddc69261b1f65c92d386b53180f301d1cf882/pure_interface-3.4.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9c34322c0f9132c7b63597db33b5025d", "sha256": "da10b32e69ca44c4394a553c00398694feeb8b7f50f96242d7487ee0c0854cba" }, "downloads": -1, "filename": "pure_interface-3.4.1.tar.gz", "has_sig": false, "md5_digest": "9c34322c0f9132c7b63597db33b5025d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31625, "upload_time": "2019-04-23T03:17:09", "url": "https://files.pythonhosted.org/packages/ea/b9/d364c8ce15344362691a6d74d5624deb68750356991958a8c733f464ea83/pure_interface-3.4.1.tar.gz" } ], "3.5.0": [ { "comment_text": "", "digests": { "md5": "9e360d0d7d5405e6fa59d953f607f951", "sha256": "34de06c02f6d57e0722dd1d96119eea615f23caeb0160a284f7419cf5229166f" }, "downloads": -1, "filename": "pure_interface-3.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "9e360d0d7d5405e6fa59d953f607f951", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19488, "upload_time": "2019-05-28T05:40:16", "url": "https://files.pythonhosted.org/packages/98/ee/e094e64bc88cdd6600195de4f20438ca1284c67f251e8b0ce13936d38f10/pure_interface-3.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "14e11b1ec8ee9b7ad3bf5a9e3f9fe9bd", "sha256": "bc8e68e83c3ecc1e135e1071b3f507f295bb6ef74d2c52d6dd1a96172d4e3fd6" }, "downloads": -1, "filename": "pure_interface-3.5.0.tar.gz", "has_sig": false, "md5_digest": "14e11b1ec8ee9b7ad3bf5a9e3f9fe9bd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26710, "upload_time": "2019-05-28T05:40:18", "url": "https://files.pythonhosted.org/packages/06/2d/9e30929e142e2c40a3b839114b93f8996d1ea99ccb0b53afc8250f80818c/pure_interface-3.5.0.tar.gz" } ], "3.5.1": [ { "comment_text": "", "digests": { "md5": "49eb657f82d44503cb777d4a1588f6bd", "sha256": "ce1073854079a6bce1e4ac79d5c2f257ce55c9ac88e9e9cfac30d3f2a1840c3b" }, "downloads": -1, "filename": "pure_interface-3.5.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "49eb657f82d44503cb777d4a1588f6bd", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19719, "upload_time": "2019-05-30T04:42:50", "url": "https://files.pythonhosted.org/packages/1d/e4/82406f73f2a125a679192c42e1d94f058a899044b6398ca2f1ebab7ac11f/pure_interface-3.5.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "51ab8a9fc11de2360aa9ac70244bab38", "sha256": "5006c943018741e7912a909be9642d8421ee0837c7b72000ef8ecd4704ee01b2" }, "downloads": -1, "filename": "pure_interface-3.5.1.tar.gz", "has_sig": false, "md5_digest": "51ab8a9fc11de2360aa9ac70244bab38", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28061, "upload_time": "2019-05-30T04:42:52", "url": "https://files.pythonhosted.org/packages/8e/ba/d6ba5f8c927fa0bd5fd8fefa4998b4514ce2277a4fba97f0bcdd49579b7b/pure_interface-3.5.1.tar.gz" } ], "3.5.2": [ { "comment_text": "", "digests": { "md5": "42f13d94988458226ee0d6a6b262e11e", "sha256": "fe40ff590288f5945f98c32750dd09c748016a03e407b24a2d6272e0769919c3" }, "downloads": -1, "filename": "pure_interface-3.5.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "42f13d94988458226ee0d6a6b262e11e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19762, "upload_time": "2019-08-02T01:39:11", "url": "https://files.pythonhosted.org/packages/69/b6/bd5967f81226ca0ee4c8f4924bc9aad1754ef26c0353f0cc0039512337ee/pure_interface-3.5.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1cc05c9d7603ff0c53997ee63defa7c9", "sha256": "92d6263bd4b34826ed9eeb66c74db9c552689ff2ece3c3c8ac87df2b9a3f4b29" }, "downloads": -1, "filename": "pure_interface-3.5.2.tar.gz", "has_sig": false, "md5_digest": "1cc05c9d7603ff0c53997ee63defa7c9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33506, "upload_time": "2019-08-01T23:01:12", "url": "https://files.pythonhosted.org/packages/6d/8a/b1fccd161a018b4e53810e8334d92715acc976cb442705bf972ca396fabd/pure_interface-3.5.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "42f13d94988458226ee0d6a6b262e11e", "sha256": "fe40ff590288f5945f98c32750dd09c748016a03e407b24a2d6272e0769919c3" }, "downloads": -1, "filename": "pure_interface-3.5.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "42f13d94988458226ee0d6a6b262e11e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19762, "upload_time": "2019-08-02T01:39:11", "url": "https://files.pythonhosted.org/packages/69/b6/bd5967f81226ca0ee4c8f4924bc9aad1754ef26c0353f0cc0039512337ee/pure_interface-3.5.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1cc05c9d7603ff0c53997ee63defa7c9", "sha256": "92d6263bd4b34826ed9eeb66c74db9c552689ff2ece3c3c8ac87df2b9a3f4b29" }, "downloads": -1, "filename": "pure_interface-3.5.2.tar.gz", "has_sig": false, "md5_digest": "1cc05c9d7603ff0c53997ee63defa7c9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 33506, "upload_time": "2019-08-01T23:01:12", "url": "https://files.pythonhosted.org/packages/6d/8a/b1fccd161a018b4e53810e8334d92715acc976cb442705bf972ca396fabd/pure_interface-3.5.2.tar.gz" } ] }