PK!Copype/__init__.pyfrom . import app PK!$pype/__main__.pyfrom . import cli cli.cli() PK!s|pype/_version.py__version__ = "0.0.69" PK!0b pype/app.py#!/usr/bin/env python """Command line pipes in python.""" from __future__ import generator_stop import collections import importlib import io import os import sys import textwrap import token import tokenize import itertools import re import contextlib import typing import types import functools import pathlib from typing import Callable from typing import Awaitable from typing import AsyncIterable from typing import AsyncIterator from typing import Optional from typing import List from typing import Dict from typing import Any import attr import parso import click import click_default_group import toolz import trio import async_generator import async_exit_stack from . import _version from . import config from . import utils from . import asynch from . import interpret from . import plug from . import interfaces async def call_traversal( self, traversal: interfaces.Traversal, items: AsyncIterable, stack: async_exit_stack.AsyncExitStack, ): runtime_parameters = {"items": items, "stack": stack} calculated_params = traversal.plugin_object.calculate_more_params(traversal) available_params = collections.ChainMap( calculated_params, runtime_parameters, traversal.specific_invocation_params, traversal.global_invocation_options.global_options, ) args = { param: available_params[param] for param in traversal.plugin_object.required_parameters } return await traversal.plugin_object.traversal_function(**args) async def program_runner( traversals: List[interfaces.Traversal], items: AsyncIterable, context: interfaces.Context, ): async with async_exit_stack.AsyncExitStack() as stack: for traversal in traversals: items = await call_traversal(context, traversal, items, stack) return stack.pop_all(), items async def async_main(basic_traversals, **kwargs): stream = trio._unix_pipes.PipeReceiveStream(os.dup(0)) receiver = asynch.TerminatedFrameReceiver(stream, b"\n") items = (item.decode() async for item in receiver) global_context = interfaces.Context(plug.global_registry.global_options.copy()) global_context.global_options.update(config.DEFAULTS) global_context.global_options.update(kwargs) global_context.global_options[ "global_namespace" ] = interpret.build_global_namespace( global_context.global_options["base_exec_before"] ) global_context.global_options["global_namespace"].update( interpret.build_global_namespace(global_context.global_options["exec_before"]) ) traversals = [] for bt in basic_traversals: for d in bt: traversal = interfaces.Traversal( global_invocation_options=global_context, specific_invocation_params=d, plugin_object=plug.global_registry.traversals[d["name"]], ) traversals.append(traversal) stack, items = await program_runner(traversals, items, global_context) async with stack: async for item in items: print(item) def main(pairs, **kwargs): trio.run(functools.partial(async_main, pairs, **kwargs)) PK!~`8"8"pype/asynch.py#!/usr/bin/env python """Command line pipes in python.""" from __future__ import generator_stop import collections import importlib import io import os import sys import textwrap import token import tokenize import itertools import re import contextlib import typing import types import functools import pathlib from typing import Callable from typing import Awaitable from typing import AsyncIterable from typing import AsyncIterator from typing import Optional from typing import List import attr import parso import click import click_default_group import toolz import trio import async_generator import async_exit_stack try: import asks except ImportError: pass else: asks.init("trio") from . import _version from . import config from . import utils T = typing.TypeVar("T") U = typing.TypeVar("U") _PYPE_VALUE = "_PYPE_VALUE" BUFSIZE = 2 ** 14 counter = itertools.count() _RECEIVE_SIZE = 4096 # pretty arbitrary async def aenumerate(items, start=0): i = start async for x in items: yield i, x i += 1 class TerminatedFrameReceiver: """Parse frames out of a Trio stream, where each frame is terminated by a fixed byte sequence. For example, you can parse newline-terminated lines by setting the terminator to b"\n". This uses some tricks to protect against denial of service attacks: - It puts a limit on the maximum frame size, to avoid memory overflow; you might want to adjust the limit for your situation. - It uses some algorithmic trickiness to avoid "slow loris" attacks. All algorithms are amortized O(n) in the length of the input. """ def __init__( self, stream: trio.abc.ReceiveStream, terminator: bytes, max_frame_length: int = 16384, ) -> None: self.stream = stream self.terminator = terminator self.max_frame_length = max_frame_length self._buf = bytearray() self._next_find_idx = 0 async def receive(self) -> bytearray: while True: terminator_idx = self._buf.find(self.terminator, self._next_find_idx) if terminator_idx < 0: # no terminator found if len(self._buf) > self.max_frame_length: raise ValueError("frame too long") # next time, start the search where this one left off self._next_find_idx = max(0, len(self._buf) - len(self.terminator) + 1) # add some more data, then loop around more_data = await self.stream.receive_some(_RECEIVE_SIZE) if more_data == b"": if self._buf: raise ValueError("incomplete frame") raise trio.EndOfChannel self._buf += more_data else: # terminator found in buf, so extract the frame frame = self._buf[:terminator_idx] # Update the buffer in place, to take advantage of bytearray's # optimized delete-from-beginning feature. del self._buf[: terminator_idx + len(self.terminator)] # next time, start the search from the beginning self._next_find_idx = 0 return frame def __aiter__(self) -> "TerminatedFrameReceiver": return self async def __anext__(self) -> bytearray: try: return await self.receive() except trio.EndOfChannel: raise StopAsyncIteration class AsyncIterableWrapper: def __init__(self, iterable): self.iterable = iter(iterable) def __aiter__(self): return self async def __anext__(self): try: return next(self.iterable) except StopIteration: raise StopAsyncIteration @async_generator.asynccontextmanager async def async_map( function: Callable[[T], Awaitable[U]], iterable: AsyncIterable[T], max_concurrent ) -> AsyncIterator[AsyncIterable[U]]: send_result, receive_result = trio.open_memory_channel[U](0) limiter = trio.CapacityLimiter(max_concurrent) async def wrapper(prev_done: trio.Event, self_done: trio.Event, item: T) -> None: async with limiter: result = await function(item) await prev_done.wait() await send_result.send(result) self_done.set() async def consume_input(nursery) -> None: prev_done = trio.Event() prev_done.set() async for item in iterable: self_done = trio.Event() nursery.start_soon(wrapper, prev_done, self_done, item, name=function) prev_done = self_done await prev_done.wait() await send_result.aclose() async with trio.open_nursery() as nursery: nursery.start_soon(consume_input, nursery) yield receive_result nursery.cancel_scope.cancel() @async_generator.asynccontextmanager async def async_map_unordered( function: Callable[[T], Awaitable[U]], iterable: AsyncIterable[T], max_concurrent ) -> AsyncIterator[AsyncIterable[U]]: send_result, receive_result = trio.open_memory_channel[U](0) limiter = trio.CapacityLimiter(max_concurrent) remaining_tasks = set() async def wrapper(task_id: int, item: T) -> None: async with limiter: result = await function(item) await send_result.send(result) remaining_tasks.remove(task_id) async def consume_input(nursery) -> None: async for task_id, item in aenumerate(iterable): remaining_tasks.add(task_id) nursery.start_soon(wrapper, task_id, item, name=function) while remaining_tasks: await trio.sleep(0) await send_result.aclose() async with trio.open_nursery() as nursery: nursery.start_soon(consume_input, nursery) yield receive_result nursery.cancel_scope.cancel() @async_generator.asynccontextmanager async def async_filter( function: Callable[[T], Awaitable[T]], iterable: AsyncIterable[T], max_concurrent ) -> AsyncIterator[AsyncIterable[T]]: send_result, receive_result = trio.open_memory_channel[T](0) limiter = trio.CapacityLimiter(max_concurrent) async def wrapper(prev_done: trio.Event, self_done: trio.Event, item: T) -> None: async with limiter: result = await function(item) await prev_done.wait() if result: await send_result.send(item) self_done.set() async def consume_input(nursery) -> None: prev_done = trio.Event() prev_done.set() async for item in iterable: self_done = trio.Event() nursery.start_soon(wrapper, prev_done, self_done, item, name=function) prev_done = self_done await prev_done.wait() await send_result.aclose() async with trio.open_nursery() as nursery: nursery.start_soon(consume_input, nursery) yield receive_result nursery.cancel_scope.cancel() SENTINEL = object() @async_generator.asynccontextmanager async def async_reduce( function: Callable[[T], Awaitable[U]], iterable: AsyncIterable[T], max_concurrent, initializer=SENTINEL, ) -> AsyncIterator[AsyncIterable[U]]: send_result, receive_result = trio.open_memory_channel[U](0) limiter = trio.CapacityLimiter(max_concurrent) collected_result = initializer async def wrapper(prev_done: trio.Event, self_done: trio.Event, item: T) -> None: nonlocal collected_result input_item = await wait_for(item) if collected_result is SENTINEL: # We are working on the first item, and initializer was not set. collected_result = input_item else: async with limiter: collected_result = await function(collected_result, input_item) await prev_done.wait() self_done.set() async def consume_input(nursery) -> None: prev_done = trio.Event() prev_done.set() async for item in iterable: self_done = trio.Event() nursery.start_soon(wrapper, prev_done, self_done, item, name=function) prev_done = self_done await prev_done.wait() await send_result.send(collected_result) await send_result.aclose() async with trio.open_nursery() as nursery: nursery.start_soon(consume_input, nursery) yield receive_result nursery.cancel_scope.cancel() def make_async(f): @functools.wraps(f) async def wrap(*args, **kwargs): return f(*args, **kwargs) return wrap async def wait_for(x): if isinstance(x, types.CoroutineType): return await x return x PK!H2 pype/cli.pyimport os import click from . import config from . import utils from . import _version from . import app from . import plug config.DEFAULTS.update( config.load_config( dir_path=os.environ.get(f"{utils.NAME}_CONFIG_DIR".upper(), None) ) ) CONTEXT_SETTINGS = {"default_map": config.DEFAULTS} @click.group(chain=True, context_settings=CONTEXT_SETTINGS) @click.option("--max-concurrent", type=int, default=config.DEFAULTS["max_concurrent"]) @click.option( "--exec-before", help="Python source code to be executed before any stage.", default=config.DEFAULTS["exec_before"], ) @click.option( "--base-exec-before", help="Python source code to be executed before any stage; typically set in the user config file. Combined with --exec-before value. ", default=config.DEFAULTS["base_exec_before"], ) @click.version_option(_version.__version__, prog_name="pype") def cli(**kwargs): pass def alias_to_click(alias): callback = lambda: [ {"name": component.name, "command": component.arguments[0]} for component in alias.components ] return click.Command(alias.name, callback=callback, short_help=alias.short_help) for subcommand_name, subcommand in plug.global_registry.cli_functions.items(): cli.add_command(subcommand, name=subcommand_name) for alias_name, alias in plug.global_registry.aliases.items(): cli.add_command(alias_to_click(alias), name=alias_name) @cli.resultcallback() def cli_main(pairs, **kwargs): app.main(pairs, **kwargs) PK!6Nqqpype/config.pyimport pathlib import appdirs import toml from . import utils from . import interpret DEFAULTS = { "max_concurrent": 5, "exec_before": None, "autocall": interpret.HowCall.SINGLE, "base_exec_before": None, } def get_config_dir(): return pathlib.Path(appdirs.user_config_dir(utils.NAME)) def load_config(dir_path=None): if dir_path is None: config_dir = get_config_dir() else: config_dir = pathlib.Path(dir_path) config_path = config_dir / "config.toml" try: with open(config_path) as f: return toml.load(f) except OSError: return {} PK!2_xpype/interfaces.pyimport types from typing import Dict from typing import Any import attr from . import plug @attr.dataclass(init=False) class Context: global_options: Dict[str, Any] = attr.ib(factory=dict) def __init__(self, global_options=attr.NOTHING): if global_options is attr.NOTHING: self.global_options = {} else: self.global_options = global_options @attr.dataclass class Traversal: """Traversal""" # ... "pype --no-autocall" global_invocation_options: Context "pype map --special reversed" specific_invocation_params: Dict[str, Any] "stack, items" runtime_parameters: Dict[str, Any] = attr.ib(default=None) "the actual traversal function" plugin_object: plug.PluginObject = attr.ib(default=None) PK!l`pqqpype/interpret.py#!/usr/bin/env python """Command line pipes in python.""" from __future__ import generator_stop import collections import importlib import io import os import sys import textwrap import token import tokenize import itertools import re import contextlib import typing import types import functools import pathlib import ast import enum from typing import Callable from typing import Awaitable from typing import AsyncIterable from typing import AsyncIterator from typing import Optional from typing import List import attr import parso import click import click_default_group import toolz import trio import async_generator import async_exit_stack from . import _version from . import config from . import utils SYMBOL = "x" class HowCall(enum.Enum): NONE = "" SINGLE = f"({SYMBOL})" VARARGS = f"(*{SYMBOL})" VARKWARGS = f"(**{SYMBOL})" class HowSig(enum.Enum): NONE = f"{SYMBOL}" SINGLE = f"{SYMBOL}" VARARGS = f"*{SYMBOL}" VARKWARGS = f"**{SYMBOL}" howcall_to_howsig = {v: HowSig.__members__[k] for k, v in HowCall.__members__.items()} @attr.dataclass class Function: wrapped: types.FunctionType global_namespace: dict source: str def __call__(self, *x): return self.wrapped(*x) def _get_named_module(name): builtins = sys.modules["builtins"] if hasattr(builtins, name): return builtins try: return __import__(name, {}, {}) except ImportError as e: pass raise LookupError(f"Could not find {name}") def _get_autoimport_module(fullname): name_parts = fullname.split(".") try_names = [] for idx in range(len(name_parts)): try_names.insert(0, ".".join(name_parts[: idx + 1])) for name in try_names: try: module = _get_named_module(name) except LookupError: pass else: if module is sys.modules["builtins"]: return {} return {name: module} return {} def find_maybe_module_names(text): # TODO: Use a real parser. return re.findall(r"\b[^\d\W]\w*(?:\.[^\d\W]\w*)+\b", text) def split_pipestring(s, sep="!"): segments = [] tree = parso.parse(s) current_nodes = [] for c in tree.children: if isinstance(c, parso.python.tree.PythonErrorLeaf) and c.value == sep: segments.append(current_nodes) current_nodes = [] else: current_nodes.append(c) segments.append(current_nodes) return ["".join(node.get_code() for node in seg) for seg in segments] def make_autocall(expression, howcall): # Don't autocall if SYMBOL appears in the expression. tree = ast.parse(expression) for node in ast.walk(tree): if isinstance(node, ast.Name) and node.id == SYMBOL: return expression return expression + howcall.value raise ValueError(howcall) def build_source(components, howcall): components = [c.strip() for c in components] components = [make_autocall(c, howcall) for c in components] indent = " " lines = "".join([f"{indent}{SYMBOL} = {c}\n" for c in components]) howsig = howcall_to_howsig[howcall] source = textwrap.dedent( f"""\ async def _pype_runner({howsig.value}): {lines} return {SYMBOL} """ ) return source def build_name_to_module(command): name_to_module = {} components = split_pipestring(command) module_names = {name for c in components for name in find_maybe_module_names(c)} for name in module_names: name_to_module.update(_get_autoimport_module(name)) return name_to_module def build_function(command, global_namespace, autocall): name_to_module = build_name_to_module(command) global_namespace = {**name_to_module, **global_namespace} source = build_source(split_pipestring(command), autocall) local_namespace = {} exec(source, global_namespace, local_namespace) function = local_namespace["_pype_runner"] return Function(function, global_namespace, source) def build_global_namespace(source): if source is None: return {} namespace = {} exec(source, {}, namespace) return namespace PK! DD pype/plug.pyimport pathlib import inspect import types import importlib import importlib.util from typing import List from typing import Dict from typing import Iterable from typing import Any import attr import pkg_resources from pype import asynch from pype import interpret from pype import utils from pype import config @attr.dataclass class PluginObject: name: str traversal_function: types.FunctionType required_parameters: List[str] calculate_more_params: types.FunctionType = attr.ib(default=lambda x: {}) @attr.dataclass class AliasStage: name: str options: List[str] arguments: List[str] @attr.dataclass class AliasCommand: name: str components: List[AliasStage] short_help: str NO_DEFAULT = attr.make_class("NO_DEFAULT", [])() @attr.dataclass class GlobalOption: name: str type: type default: type(NO_DEFAULT) class Registry: def __init__( self, traversals=None, global_options=None, cli_functions=None, aliases=None ): self.traversals: Dict[str, PluginObject] = traversals or {} self.global_options: Dict[str, GlobalOption] = global_options or {} self.cli_functions: Dict[str, Any] = cli_functions or {} self.aliases: Dict[str, AliasCommand] = aliases or {} def register(self, name=None, params=None): def wrap(function): if name is None: registered_name = function.__name__ else: registered_name = name self.traversals[registered_name] = PluginObject( registered_name, function, params ) return function return wrap def add_traversal(self, name=None, calculate_more_params=lambda x: {}): def wrap(function): if name is None: registered_name = function.__name__ else: registered_name = name params = [param for param in inspect.signature(function).parameters.keys()] self.traversals[registered_name] = PluginObject( registered_name, function, params, calculate_more_params ) return function return wrap def add_cli(self, name=None): def wrap(function): if name is None: registered_name = function.__name__ else: registered_name = name self.cli_functions[registered_name] = function return function return wrap # Currently, pype reserves `function`, `command`, `stack`, `items`, `global_namespace`. # These could all be provided in a namespace object. def plugin_module_paths() -> List[str]: return [ entry_point.module_name + "." + entry_point.name for entry_point in pkg_resources.iter_entry_points(f"{utils.NAME}_plugins") ] def collect_modules(import_paths: Iterable[str]) -> List[types.ModuleType]: modules = [] for path in import_paths: modules.append(importlib.import_module(path)) return modules def combine_registries(registries): global_options = {} traversals = {} cli_functions = {} aliases = {} for registry in registries: traversals.update(registry.traversals) global_options.update(registry.global_options) cli_functions.update(registry.cli_functions) aliases.update(registry.aliases) return Registry(traversals, global_options, cli_functions, aliases) def make_plugin_registry(): plugin_modules = collect_modules(plugin_module_paths()) plugin_registries = [module.registry for module in plugin_modules] return combine_registries(plugin_registries) def make_config_registry(): modules = import_config_dir_modules() return combine_registries(module.registry for module in modules) def load_module(path): module_name = "user_config." + path.with_suffix("").name spec = importlib.util.spec_from_file_location(module_name, str(path)) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module def import_config_dir_modules(user_config_dir=None): if user_config_dir is None: user_config_dir = config.get_config_dir() modules = [] for path in (pathlib.Path(user_config_dir) / "modules").rglob("*.py"): module = load_module(path) modules.append(module) return modules def make_global_registry(): return combine_registries( [make_plugin_registry(), make_config_registry(), make_config_aliases_registry()] ) def make_synthetic_command(cmd,): components = [ AliasStage(d["name"], d["options"], d["arguments"]) for d in cmd["stage"] ] return AliasCommand(cmd["name"], components, cmd["short_help"]) def make_aliases(conf): synth_commands = [] if 'alias' not in conf: return [] for cmd in conf["alias"]: synth_commands.append(make_synthetic_command(cmd)) return synth_commands def make_config_aliases_registry(): conf = config.load_config() commands = make_aliases(conf) return Registry(aliases={c.name: c for c in commands}) global_registry = make_global_registry() PK!"r`5pype/plugins/basic.pyimport click from pype import plug from pype import asynch from pype import interpret registry = plug.Registry() def calculate_function(traversal, autocall=None): if autocall is None: autocall = traversal.global_invocation_options.global_options["autocall"] return { "function": interpret.build_function( traversal.specific_invocation_params["command"], traversal.global_invocation_options.global_options["global_namespace"], autocall, ) } def calculate_reduce(traversal): function = interpret.build_function( traversal.specific_invocation_params["command"], traversal.global_invocation_options.global_options["global_namespace"], autocall=interpret.HowCall.VARARGS, ) return {"function": function} @registry.add_traversal("map", calculate_more_params=calculate_function) async def map(function, items, stack, max_concurrent): return await stack.enter_async_context( asynch.async_map(function, items, max_concurrent) ) @registry.add_traversal("map_unordered", calculate_more_params=calculate_function) async def map_unordered(function, items, stack, max_concurrent): return await stack.enter_async_context( asynch.async_map_unordered(function, items, max_concurrent) ) @registry.add_traversal("filter", calculate_more_params=calculate_function) async def filter(function, items, stack, max_concurrent): return await stack.enter_async_context( asynch.async_filter(function, items, max_concurrent) ) @registry.add_traversal("apply", calculate_more_params=calculate_function) async def apply(function, items): return asynch.AsyncIterableWrapper([await function([x async for x in items])]) @registry.add_traversal( "eval", calculate_more_params=lambda x: calculate_function( x, autocall=interpret.HowCall.NONE ), ) async def eval(function): return asynch.AsyncIterableWrapper([await function(None)]) @registry.add_traversal("stack", calculate_more_params=calculate_function) async def stack(function, items): return asynch.AsyncIterableWrapper( [await function("".join([x + "\n" async for x in items]))] ) @registry.add_traversal("reduce", calculate_more_params=calculate_reduce) async def reduce(function, items, stack, max_concurrent): return await stack.enter_async_context( asynch.async_reduce(function, items, max_concurrent) ) subcommands = [ click.Command("map", short_help="Call on each line of input."), click.Command("apply", short_help="Call on input as a sequence."), click.Command( "filter", short_help="Call on each line of input and exclude false values.", ), click.Command("eval", short_help="Call without any input."), click.Command( "stack", short_help="Call on input as a single concatenated string." ), click.Command( "map-unordered", short_help="Call on each line of input, ignoring order of input items.", ), ] def build_callback(sub_command): def callback(command): return [{"name": sub_command.name.replace("-", "_"), "command": command}] return callback for subcommand in subcommands: subcommand.params = [click.Argument(["command"])] subcommand.callback = build_callback(subcommand) # TODO: add_cli and add_traversal should be the non-decorator form registry.add_cli(name=subcommand.name)(subcommand) @registry.add_cli(name="reduce") @click.command( "reduce", short_help="Reduce a sequence with a . e.g. `operator.mul`." ) @click.argument("function_name") def _reduce(function_name): return [{"command": f"toolz.curry({function_name})", "name": "reduce"}] PK!w pype/utils.pyNAME = "pype" PK!H˚:H-python_pype-0.0.69.dist-info/entry_points.txtN+I/N.,()*,HV9z@ 䔦gU$%g&AŸPK!HڽTU"python_pype-0.0.69.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!Hmv( U%python_pype-0.0.69.dist-info/METADATAX[8~9'IOt4СL,GIDۖגI2 J'iz}<ėJU_B>) -U6fp|m*\50< o4zni?`̅f2cJE?s0?^์E/XZW)Iob<aO) NƘ=8; Noyµ3)uOSsKc᝿FGR(ϧ{:/JKmx|u=}.2Qp3풍9)|9n'r_}ٟ/ӟwjQiN%,  27Ъ2#2ӿ@+3X m owW g _ 3 QayX"R!pcQFD4 +#=1a)*,\.;==mI|гYL<R8 Qt+0uV6X$QXzL&pgycPg'Y^ȝݗS< [;Pn̖Ht'?uk_˰VNIZZk?J*F_=<qQGQp~o=Y9d>#s0IBq@+ h$W|Iɍ|E]R!f-tC>z,gm{mќ>o̽bGp[ϭEk̆a&pU/ZzעSصit\-\^=ܛ,kn!cS*Qg> Wyspm37}#4B_6 `PYjm_|:)Qr3&S~?ZHhA_;6B$Te,G2{w dnV1";{MTFÄڅZu[so4 NxwVSFJm@,]"rz\ߨdUɷT [M`Pr{}l1/S${Ʃ&]+$^%|1Wb;nsp>P ^\ /BD^Uy=ƄfagFE15}ygv^|q#o~5Q~>n`3UJMgC loE_Q)Kd4ϮߵdZ/|kx{Oj'/WZ .&ڴ ee*,fЀf@2ڄ5Nlx W 9 dOmқZձTU3[i\2zEr,c"gl` RK,0E ۲+ _Wu m+MYٍv u R,pǔ>heuAtisʑ\ /(i<"]( q'[oФ]Z aZ z'r nXeC75_ulJUvf Kr(ll@J`V…A VfR$װ%g c GPK!HL#python_pype-0.0.69.dist-info/RECORDۖkX,T$An AXZNyީov7.m( ?yD2_jJEi("u(WnM1(f^٭R MT2 yY2~}?s=q^ 0/\KqZjY:ls<`HRm@eoXY abA0$na}U9.nL+fe"g2wE%lx_A5ySS E!T>:pltEb%/U{7[ hq|b'[Ze B[ss ( >X#~4i%lό"=JgK 4BH>$F4n`(<ބy/CpU^IW|Duaȹ~PQc+ס؍HtT(ǎ= _t1PK!Copype/__init__.pyPK!$@pype/__main__.pyPK!s|pype/_version.pyPK!0b pype/app.pyPK!~`8"8"큇 pype/asynch.pyPK!H2 /pype/cli.pyPK!6Nqq 6pype/config.pyPK!2_x8pype/interfaces.pyPK!l`pqq;pype/interpret.pyPK! DD Lpype/plug.pyPK!"r`5`pype/plugins/basic.pyPK!w ppype/utils.pyPK!H˚:H-Gppython_pype-0.0.69.dist-info/entry_points.txtPK!HڽTU"ppython_pype-0.0.69.dist-info/WHEELPK!Hmv( U%`qpython_pype-0.0.69.dist-info/METADATAPK!HL#{python_pype-0.0.69.dist-info/RECORDPK*~