PK!"88cafe/__init__.py__import__("pkg_resources").declare_namespace(__name__) PK!<0cafe/abc/__init__.pyfrom abc import ABCMeta class AbstractClass(object): __metaclass__ = ABCMeta # noinspection PyUnresolvedReferences @classmethod def __subclasshook__(cls, other_class): return super(AbstractClass, cls).__subclasshook__(other_class) and all( any(x in B.__dict__ for B in other_class.__mro__) for x in cls.__abstractmethods__ ) PK!^KFcafe/abc/compat.pyfrom six import PY2 if PY2: # noinspection PyPep8Naming,SpellCheckingInspection,PyShadowingBuiltins class abstractclassmethod(classmethod): __isabstractmethod__ = True def __init__(self, callable): callable.__isabstractmethod__ = True super(abstractclassmethod, self).__init__(callable) else: # noinspection PyUnresolvedReferences from abc import abstractclassmethod PK!}t%ocafe/compat.pytry: # noinspection PyUnresolvedReferences long except NameError: # noinspection PyShadowingBuiltins long = int PK!cafe/datastructs/__init__.pyPK!7}}cafe/datastructs/dict.pyfrom copy import deepcopy from json import loads, load, dumps from os.path import isfile from cafe.patterns.borg import Borg from cafe.utilities import is_str class AttributeDict(dict): """ A dictionary implementation that allows for all keys to be used as an attribute. In this implementation we do proper get/setattr override here, no self.__dict__ mambo jumbo. """ def __init__(self, *args, **kwargs): super(AttributeDict, self).__init__(*args, **kwargs) def __getattr__(self, item): if item in self: return self[item] raise AttributeError("Could not get attr: '{}' from '{}'".format(item, self)) def __setattr__(self, key, value): self[key] = value class DeepAttributeDict(AttributeDict): """ A DeepAttributeDict is an AttributeDict of which dict objects at all depths are converted to DeepAttributeDict. """ def __init__(self, *args, **kwargs): super(DeepAttributeDict, self).__init__(*args, **kwargs) self._deep_init() def _deep_init(self): for key, value in self.items(): if isinstance(value, dict) and not isinstance(value, AttributeDict): self[key] = DeepAttributeDict(value) class MergingDict(AttributeDict): """ A MergingDict is an AttributeDict whose attribute/item values are always merged if the rvalue implements an update or append method. If the rvalue is not merge-able, it is simply replaced. """ def replace(self, key, value): """ Convenience method provided as a way to replace a value mapped by a key.This is required since a MergingDict always merges via assignment of item/attribute. :param key: Attribute name or item key to replace rvalue for. :type key: object :param value: The new value to assign. :type value: object :return: """ super(MergingDict, self).__setitem__(key, value) def update(self, other=None, **kwargs): """ A special update method to handle merging of dict objects. For all other iterable objects, we use the parent class update method. For other objects, we simply make use of the internal merging logic. :param other: An iterable object. :type other: dict or object :param kwargs: key/value pairs to update. :rtype: None """ if other is not None: if isinstance(other, dict): for key in other: self[key] = other[key] else: # noinspection PyTypeChecker super(MergingDict, self).update(other) for key in kwargs: self._merge(key, kwargs[key]) def _merge_method(self, key): """ Identify a merge compatible method available in self[key]. Currently we support 'update' and 'append'. :param key: Attribute name or item key :return: Method name usable to merge a value into the instance mapped by key :rtype: str """ if key in self: for method in ["update", "append"]: if hasattr(self[key], method): return method return None def _merge(self, key, value): """ Internal merge logic implementation to allow merging of values when setting attributes/items. :param key: Attribute name or item key :type key: str :param value: Value to set attribute/item as. :type value: object :rtype: None """ method = self._merge_method(key) if method is not None: # strings are special, update methods like set.update looks for # iterables if method == "update" and is_str(value): value = [value] if ( method == "append" and isinstance(self[key], list) and isinstance(value, list) ): # if rvalue is a list and given object is a list, we expect all # values to be appended method = "extend" getattr(self[key], method)(value) else: super(MergingDict, self).__setitem__(key, value) def __setitem__(self, key, value): self._merge(key, value) def __setattr__(self, key, value): self._merge(key, value) class DeepMergingDict(MergingDict): """ A DeepMergingDict is a MergingDict of which dict objects at all depths are converted to DeepMergingDicts. """ def __init__(self, *args, **kwargs): super(DeepMergingDict, self).__init__(*args, **kwargs) self._deep_init() @staticmethod def _should_cast(value): return isinstance(value, dict) and not isinstance(value, MergingDict) def _deep_init(self): for key, value in self.items(): if self._should_cast(value): self.replace(key, DeepMergingDict(value)) def replace(self, key, value): if self._should_cast(value): value = DeepMergingDict(value) super(DeepMergingDict, self).replace(key, value) def update(self, other=None, **kwargs): if self._should_cast(other): other = DeepMergingDict(other) super(DeepMergingDict, self).update(other, **kwargs) class BorgDict(Borg, dict): """ An dict implementing the Borg Pattern. This can be extended via inheritance. In this implementation the dict itself is not used. All actions are mapped to the Borg shared state. """ def __init__(self, *args, **kwargs): super(BorgDict, self).__init__() self.update(*args, **kwargs) def update(self, *args, **kwargs): self.__dict__.update(*args, **kwargs) def __setitem__(self, key, value): setattr(self, key, value) def __getitem__(self, key): return getattr(self, key) def __delitem__(self, key): delattr(self, key) def __repr__(self): return self.__dict__.__repr__() def __str__(self): return self.__dict__.__str__() def __iter__(self): return iter(self.__dict__) def __len__(self): return len(self.__dict__) def __contains__(self, k): return self.__dict__.__contains__(k) def keys(self): return self.__dict__.keys() def get(self, *args, **kwargs): return self.__dict__.get(*args, **kwargs) def pop(self, *args, **kwargs): return self.__dict__.pop(*args, **kwargs) class JSONAttributeDict(AttributeDict): """ :type source: str or dict or cafe.datastructs.dict.JSONAttributeDict """ def __init__(self, source): super(JSONAttributeDict, self).__init__() try: self.update(loads(source) if is_str(source) else deepcopy(source)) except ValueError: if isfile(source): with open(source) as sf: self.update(load(sf)) else: raise ValueError(source) @property def pretty(self): return dumps(self, indent=2) def __str__(self): return self.pretty def __repr__(self): return self.pretty PK! 6cafe/datastructs/memory.pyfrom enum import Enum from re import match from cafe.compat import long BYTES = 1 KB = 1024 * BYTES MB = 1024 * KB GB = 1024 * MB TB = 1024 * GB class MemoryUnit(Enum): BYTES = BYTES KB = KB MB = MB GB = GB TB = TB class Memory(long): # noinspection PyInitNewSignature def __new__(cls, x, unit=None): if isinstance(x, str): units_regex = "|".join(MemoryUnit.__members__.keys()) m = match(r"^(\d+) ?({})$".format(units_regex), x) if m is None: raise ValueError( '{} requires am integer or a string in the format "' ' ({})"'.format(Memory.__class__.__name__, units_regex) ) x = int(m.group(1)) * MemoryUnit.__members__.get(m.group(2)).value elif unit is None: raise ValueError("No unit provided.") else: x = x * unit.value # noinspection PyTypeChecker return super(Memory, cls).__new__(cls, x) PK!T{"cafe/datastructs/units/__init__.pyfrom re import match try: long except NameError: # noinspection PyShadowingBuiltins long = int class BaseUnitClass(float): UNITS = {} # noinspection PyInitNewSignature def __new__(cls, x, unit=None): if isinstance(x, str): units_regex = "|".join(cls.UNITS.keys()) m = match(r"^(\d+(.\d+)?) ?({})$".format(units_regex), x) if m is None: raise ValueError( '{} requires number or a string in the format " ' '({})"'.format(cls.__name__, units_regex) ) x = float(m.group(1)) * cls.UNITS.get(m.group(3)) elif unit is None: raise ValueError("No unit provided.") else: x = x * cls.UNITS[unit] return super(BaseUnitClass, cls).__new__(cls, x) def __getattr__(self, item): if item in self.UNITS: # if unit is known convert to unit result = self * 1.0 / self.UNITS[item] rounded = long(result) return result if result != rounded else rounded raise AttributeError("{} is not a valid conversion unit".format(item)) PK!Kg9cafe/datastructs/units/data.pyfrom enum import Enum from cafe.datastructs.units import BaseUnitClass class DataMultiplier(Enum): k = 10 ** 3 M = 10 ** 6 G = 10 ** 9 T = 10 ** 12 P = 10 ** 15 E = 10 ** 18 Z = 10 ** 21 Y = 10 ** 24 Ki = 2 ** 10 Mi = 2 ** 20 Gi = 2 ** 30 Ti = 2 ** 40 Pi = 2 ** 50 Ei = 2 ** 60 class DataBaseUnit(Enum): b = 1 bit = 1 B = 8 byte = 8 class DataUnit(BaseUnitClass): """ A data unit object internally stores the number of bits associated. Eg: DataUnit(1, 'byte') == 8 """ UNITS = { "{}{}".format(multiplier, base): DataMultiplier[multiplier].value * DataBaseUnit[base].value for multiplier in DataMultiplier.__members__ for base in DataBaseUnit.__members__ } UNITS.update({base: DataBaseUnit[base].value for base in DataBaseUnit.__members__}) # noinspection PyInitNewSignature def __new__(cls, x, unit=None): if unit is None: # noinspection PyUnresolvedReferences unit = DataBaseUnit.bit.name return super(DataUnit, cls).__new__(cls, x, unit) class DataRateUnit(DataUnit): """ A data rate unit object internally stores the number bits per second. """ UNITS = { "{}{}".format(unit, suffix): DataUnit.UNITS[unit] for unit in DataUnit.UNITS for suffix in ["/s", "ps"] } # noinspection PyInitNewSignature def __new__(cls, x, unit=None): if unit is None: # noinspection PyUnresolvedReferences unit = "{}ps".format(DataBaseUnit.bit.name) return super(DataUnit, cls).__new__(cls, x, unit) PK!X<cafe/decorators/__init__.py# noinspection PyUnresolvedReferences from cafe.abc.compat import abstractclassmethod # noqa F401 # noinspection PyPep8Naming,SpellCheckingInspection class classproperty(property): """ A decorator that behaves like @property except that operates on classes rather than instances. Original Implementation: sqlalchemy.util.langhelpers.classproperty """ def __init__(self, fget, *arg, **kw): super(classproperty, self).__init__(fget, *arg, **kw) self.__doc__ = fget.__doc__ # noinspection PyMethodOverriding,PyArgumentList,PyMethodParameters def __get__(desc, self, cls): return desc.fget(cls) PK!y@dcafe/logging/__init__.pyfrom logging import getLogger, debug, exception, root from logging.config import dictConfig from os import getenv from os.path import isfile from yaml import safe_load as load from cafe.logging.trace import LOGGING_LEVELS from cafe.patterns.mixins import ContextMixin from cafe.utilities import is_str class LoggingManager(object): CONFIGFILE_ENV_KEY = "LOG_CFG" @classmethod def set_level(cls, level): """ :raises: ValueError """ level = ( level if not is_str(level) else int(LOGGING_LEVELS.get(level.upper(), level)) ) for handler in root.handlers: handler.setLevel(level) root.setLevel(level) @classmethod def load_config(cls, configfile="logging.yaml"): """ :raises: ValueError """ configfile = getenv(cls.CONFIGFILE_ENV_KEY, configfile) if isfile(configfile): with open(configfile, "r") as cf: # noinspection PyBroadException try: dictConfig(load(cf)) except ValueError: debug("Learn to config foooo! Improper config at %s", configfile) except Exception: exception("Something went wrong while reading %s.", configfile) else: raise ValueError("Invalid configfile specified: {}".format(configfile)) # noinspection PyPep8Naming class LoggedObject(ContextMixin): def __new__(cls, *args, **kwargs): cls.logger = getLogger("{}.{}".format(cls.__module__, cls.__name__)) """:type: cafe.logging.trace.TraceEnabledLogger""" cls.logger.trace("Instantiating %s.%s", cls.__module__, cls.__qualname__) return super(LoggedObject, cls).__new__(cls) def __enter__(self): self.logger.trace( "Entering context for %s.%s", self.__module__, self.__class__.__qualname__ ) return super(LoggedObject, self).__enter__() def __exit__(self, exc_type, exc_val, exc_tb): self.logger.trace( "Exiting context for %s.%s", self.__module__, self.__class__.__qualname__ ) super(LoggedObject, self).__exit__(exc_type, exc_val, exc_tb) PK!yMcafe/logging/trace.pyimport logging TRACE = 5 logging.addLevelName(5, "TRACE") logging.TRACE = 5 def trace(self, msg, *args, **kwargs): """ Log 'msg % args' with severity 'TRACE'. To pass exception information, use the keyword argument exc_info with a true value, e.g. logger.trace("Houston, we have a %s", "thorny problem", exc_info=1) """ if self.isEnabledFor(TRACE): self._log(TRACE, msg, args, **kwargs) class TraceEnabledLogger(logging.Logger): trace = trace logging.Logger.trace = trace try: # noinspection PyProtectedMember LOGGING_LEVELS = logging._levelToName except AttributeError: # noinspection PyProtectedMember LOGGING_LEVELS = logging._levelNames PK!cafe/patterns/__init__.pyPK!:jScafe/patterns/borg.pyclass BorgStateManager(object): """ A special State Manager for Borg classes and child classes. This is what makes it possible for child classes to maintain their own state different to both parents, siblings and their own children. This itself implements the Borg pattern so that all its instances have a shared state. Each class state is mapped to the the hash of the class itself. """ __shared_state = {} def __init__(self): self.__dict__ = self.__shared_state @classmethod def get_state(cls, clz): """ Retrieve the state of a given Class. :param clz: types.ClassType :return: Class state. :rtype: dict """ if clz not in cls.__shared_state: cls.__shared_state[clz] = ( clz.init_state() if hasattr(clz, "init_state") else {} ) return cls.__shared_state[clz] class Borg(object): """ A Borg pattern base class. Usable on its own or via inheritance. Uses `cafe.patterns.borg.BorgStateManager` internally to achieve state separation for children and grand children. See http://code.activestate.com/recipes/66531-singleton-we-dont-need-no-stinkin-singleton-the-bo/ for more # noqa information regarding the Borg Pattern. """ def __init__(self): self.__dict__ = self._shared_state @classmethod def init_state(cls): return {} @property def _shared_state(self): return BorgStateManager.get_state(self.__class__) PK!|ídKK!cafe/patterns/context/__init__.pyclass SessionManager(object): def __init__(self, factory, *args, **kwargs): self._kwargs = kwargs self._args = args self._factory = factory self.session = None def open(self): if self.session is None: self.session = self._factory(*self._args, **self._kwargs) def close(self): if self.session is not None: self.session.close() self.session = None def __enter__(self): self.open() return self.session def __exit__(self, exc_type, exc_val, exc_tb): self.close() PK!Ocafe/patterns/mixins.pyclass ContextMixin(object): def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): pass PK!Aucafe/twisted/__init__.pytry: # noinspection PyPackageRequirements,PyUnresolvedReferences from twisted.internet import defer, reactor def async_sleep(seconds): """ An asynchronous sleep function using twsited. Source: http://twistedmatrix.com/pipermail/twisted-python/2009-October/020788.html # noqa :type seconds: int """ d = defer.Deferred() # noinspection PyUnresolvedReferences reactor.callLater(seconds, d.callback, seconds) return d except ImportError: pass PK!ߢZZcafe/utilities.pyfrom os import getenv from six import string_types # noinspection SpellCheckingInspection def listify(arg): """ Simple utility method to ensure an argument provided is a list. If the provider argument is not an instance of `list`, then we return [arg], else arg is returned. :type arg: list :rtype: list """ if isinstance(arg, (set, tuple)): # if it is a set or tuple make it a list return list(arg) if not isinstance(arg, list): return [arg] return arg def is_str(arg): """ A py2/3 compatible 'is string' check. :type arg: :rtype: """ return isinstance(arg, string_types) def resolve_setting(default, arg_value=None, env_var=None, config_value=None): """ Resolves a setting for a configuration option. The winning value is chosen from multiple methods of configuration, in the following order of priority (top first): - Explicitly passed argument - Environment variable - Configuration file entry - Default :param arg_value: Explicitly passed value :param env_var: Environment variable name :type env_var: string or None :param config_value: Configuration entry :param default: Default value to if there are no overriding options :return: Configuration value """ if arg_value is not None: return arg_value else: env_value = getenv(env_var) if env_value is not None: return env_value else: if config_value is not None: return config_value else: return default PK!%0u^,^,$python_cafe-0.17.0.dist-info/LICENSE Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. PK!H|n-WY"python_cafe-0.17.0.dist-info/WHEEL A н#Z;/" bFF]xzwK;<*mTֻ0*Ri.4Vm0[H, JPK!HIڌ?%python_cafe-0.17.0.dist-info/METADATATKs0W,9A'V^24Ӵ08dͿgU'mR8bI}VD/seSF  k4:٣G桪] =@ƐBPgdAkV*WiPAZjq\2zV;> t, !噩z2ս]?'*C{;26e@FK٠LLK~*HphXx _AYtIZ'C~ԅW'#b] ?`gtN-ڣ1qț =!q5qHTڏ)KYG"AcHkjtȃ{5U &ma[71C5:tߩСCsq48]w_2jO&g&6On5u{߻Oq3iH2//]seHrWU>-пΰY3c;k?PK!HB6#python_cafe-0.17.0.dist-info/RECORDɖH}> d1#Z("(†$@m*=m,o(;!r?;Z3kGRw5l֚ZpcJ˽LůeTu\"f5٘Lm׊cn\'aϊ ѓM=M;|ȷ IH.Zƴy.0C-~I7ڃ Nbc+lxkH/% Q#8Ĩ5#ï%-⁣.jb:X}Yh5ח0l]L9!5E)\LuY54vԶ94(P&@nt INSecr'+ 7YIwrxrR}s).W.$YMHr"/L`$7Xw0NCfKL ])Ll|(ai]qA*]G?o5+"X@x'w=y pi~( j@ ,R6xG{/@ݘ %y-w#nK^c?PK!"88cafe/__init__.pyPK!<0fcafe/abc/__init__.pyPK!^KFcafe/abc/compat.pyPK!}t%ocafe/compat.pyPK!cafe/datastructs/__init__.pyPK!7}}cafe/datastructs/dict.pyPK! 6!cafe/datastructs/memory.pyPK!T{"%cafe/datastructs/units/__init__.pyPK!Kg9*cafe/datastructs/units/data.pyPK!X<Y1cafe/decorators/__init__.pyPK!y@d4cafe/logging/__init__.pyPK!yM!=cafe/logging/trace.pyPK!@cafe/patterns/__init__.pyPK!:jSN@cafe/patterns/borg.pyPK!|ídKK!Fcafe/patterns/context/__init__.pyPK!OIcafe/patterns/mixins.pyPK!AuIcafe/twisted/__init__.pyPK!ߢZZ"Lcafe/utilities.pyPK!%0u^,^,$Rpython_cafe-0.17.0.dist-info/LICENSEPK!H|n-WY"Kpython_cafe-0.17.0.dist-info/WHEELPK!HIڌ?%python_cafe-0.17.0.dist-info/METADATAPK!HB6#dpython_cafe-0.17.0.dist-info/RECORDPK+|