penguiflow 1.0.2__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of penguiflow might be problematic. Click here for more details.
- penguiflow/__init__.py +27 -2
- penguiflow/core.py +729 -54
- penguiflow/errors.py +113 -0
- penguiflow/metrics.py +105 -0
- penguiflow/middlewares.py +6 -7
- penguiflow/patterns.py +47 -5
- penguiflow/policies.py +149 -0
- penguiflow/streaming.py +142 -0
- penguiflow/testkit.py +269 -0
- penguiflow/types.py +15 -1
- penguiflow/viz.py +181 -1
- {penguiflow-1.0.2.dist-info → penguiflow-2.0.0.dist-info}/METADATA +181 -19
- penguiflow-2.0.0.dist-info/RECORD +18 -0
- penguiflow-1.0.2.dist-info/RECORD +0 -13
- {penguiflow-1.0.2.dist-info → penguiflow-2.0.0.dist-info}/WHEEL +0 -0
- {penguiflow-1.0.2.dist-info → penguiflow-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {penguiflow-1.0.2.dist-info → penguiflow-2.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: penguiflow
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Async agent orchestration primitives.
|
|
5
5
|
Author: PenguiFlow Team
|
|
6
6
|
License: MIT License
|
|
@@ -26,7 +26,7 @@ License: MIT License
|
|
|
26
26
|
SOFTWARE.
|
|
27
27
|
|
|
28
28
|
Project-URL: Homepage, https://github.com/penguiflow/penguiflow
|
|
29
|
-
Requires-Python: >=3.
|
|
29
|
+
Requires-Python: >=3.11
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
License-File: LICENSE
|
|
32
32
|
Requires-Dist: pydantic>=2.6
|
|
@@ -34,6 +34,8 @@ Provides-Extra: dev
|
|
|
34
34
|
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
35
35
|
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
36
36
|
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
38
|
+
Requires-Dist: coverage[toml]>=7.0; extra == "dev"
|
|
37
39
|
Requires-Dist: ruff>=0.2; extra == "dev"
|
|
38
40
|
Dynamic: license-file
|
|
39
41
|
|
|
@@ -43,6 +45,21 @@ Dynamic: license-file
|
|
|
43
45
|
<img src="asset/Penguiflow.png" alt="PenguiFlow logo" width="220">
|
|
44
46
|
</p>
|
|
45
47
|
|
|
48
|
+
<p align="center">
|
|
49
|
+
<a href="https://github.com/penguiflow/penguiflow/actions/workflows/ci.yml">
|
|
50
|
+
<img src="https://github.com/penguiflow/penguiflow/actions/workflows/ci.yml/badge.svg" alt="CI Status">
|
|
51
|
+
</a>
|
|
52
|
+
<a href="https://github.com/penguiflow/penguiflow">
|
|
53
|
+
<img src="https://img.shields.io/badge/coverage-85%25-brightgreen" alt="Coverage">
|
|
54
|
+
</a>
|
|
55
|
+
<a href="https://pypi.org/project/penguiflow/">
|
|
56
|
+
<img src="https://img.shields.io/pypi/v/penguiflow.svg" alt="PyPI version">
|
|
57
|
+
</a>
|
|
58
|
+
<a href="https://github.com/penguiflow/penguiflow/blob/main/LICENSE">
|
|
59
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License">
|
|
60
|
+
</a>
|
|
61
|
+
</p>
|
|
62
|
+
|
|
46
63
|
**Async-first orchestration library for multi-agent and data pipelines**
|
|
47
64
|
|
|
48
65
|
PenguiFlow is a **lightweight Python library** to orchestrate agent flows.
|
|
@@ -52,8 +69,14 @@ It provides:
|
|
|
52
69
|
* **Concurrent fan-out / fan-in patterns**
|
|
53
70
|
* **Routing & decision points**
|
|
54
71
|
* **Retries, timeouts, backpressure**
|
|
72
|
+
* **Streaming chunks** (LLM-style token emission with `Context.emit_chunk`)
|
|
55
73
|
* **Dynamic loops** (controller nodes)
|
|
56
74
|
* **Runtime playbooks** (callable subflows with shared metadata)
|
|
75
|
+
* **Per-trace cancellation** (`PenguiFlow.cancel` with `TraceCancelled` surfacing in nodes)
|
|
76
|
+
* **Deadlines & budgets** (`Message.deadline_s`, `WM.budget_hops`, and `WM.budget_tokens` guardrails that you can leave unset/`None`)
|
|
77
|
+
* **Observability hooks** (`FlowEvent` callbacks for logging, MLflow, or custom metrics sinks)
|
|
78
|
+
* **Policy-driven routing** (optional policies steer routers without breaking existing flows)
|
|
79
|
+
* **Traceable exceptions** (`FlowError` captures node/trace metadata and optionally emits to Rookery)
|
|
57
80
|
|
|
58
81
|
Built on pure `asyncio` (no threads), PenguiFlow is small, predictable, and repo-agnostic.
|
|
59
82
|
Product repos only define **their models + node functions** — the core stays dependency-light.
|
|
@@ -86,6 +109,7 @@ msg = Message(
|
|
|
86
109
|
payload=QueryIn(text="unique reach last 30 days"),
|
|
87
110
|
headers=Headers(tenant="acme")
|
|
88
111
|
)
|
|
112
|
+
msg.meta["request_id"] = "abc123"
|
|
89
113
|
```
|
|
90
114
|
|
|
91
115
|
### Node
|
|
@@ -99,12 +123,18 @@ from penguiflow.node import Node
|
|
|
99
123
|
class QueryOut(BaseModel):
|
|
100
124
|
topic: str
|
|
101
125
|
|
|
102
|
-
async def triage(
|
|
126
|
+
async def triage(msg: QueryIn, ctx) -> QueryOut:
|
|
103
127
|
return QueryOut(topic="metrics")
|
|
104
128
|
|
|
105
129
|
triage_node = Node(triage, name="triage")
|
|
106
130
|
```
|
|
107
131
|
|
|
132
|
+
Node functions must always accept **two positional parameters**: the incoming payload and
|
|
133
|
+
the `Context` object. If a node does not use the context, name it `_` or `_ctx`, but keep
|
|
134
|
+
the parameter so the runtime can still inject it. Registering the node with
|
|
135
|
+
`ModelRegistry` ensures the payload is validated/cast to the expected Pydantic model;
|
|
136
|
+
setting `NodePolicy(validate="none")` skips that validation for hot paths.
|
|
137
|
+
|
|
108
138
|
### Flow
|
|
109
139
|
|
|
110
140
|
A flow wires nodes together in a directed graph.
|
|
@@ -178,13 +208,77 @@ await flow.stop()
|
|
|
178
208
|
pip install -e ./penguiflow
|
|
179
209
|
```
|
|
180
210
|
|
|
181
|
-
Requires **Python 3.
|
|
211
|
+
Requires **Python 3.11+**.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 🛠️ Key capabilities
|
|
216
|
+
|
|
217
|
+
### Streaming & incremental delivery
|
|
218
|
+
|
|
219
|
+
`Context.emit_chunk` (and `PenguiFlow.emit_chunk`) provide token-level streaming without
|
|
220
|
+
sacrificing backpressure or ordering guarantees. The helper wraps the payload in a
|
|
221
|
+
`StreamChunk`, mirrors routing metadata from the parent message, and automatically
|
|
222
|
+
increments per-stream sequence numbers. See `tests/test_streaming.py` and
|
|
223
|
+
`examples/streaming_llm/` for an end-to-end walk-through.
|
|
224
|
+
|
|
225
|
+
### Reliability & guardrails
|
|
226
|
+
|
|
227
|
+
PenguiFlow enforces reliability boundaries out of the box:
|
|
228
|
+
|
|
229
|
+
* **Per-trace cancellation** (`PenguiFlow.cancel(trace_id)`) unwinds a single run while
|
|
230
|
+
other traces keep executing. Worker tasks observe `TraceCancelled` and clean up
|
|
231
|
+
resources; `tests/test_cancel.py` covers the behaviour.
|
|
232
|
+
* **Deadlines & budgets** let you keep loops honest. `Message.deadline_s` guards
|
|
233
|
+
wall-clock execution, while controller payloads (`WM`) track hop and token budgets.
|
|
234
|
+
Exhaustion short-circuits into terminal `FinalAnswer` messages as demonstrated in
|
|
235
|
+
`tests/test_budgets.py` and `examples/controller_multihop/`.
|
|
236
|
+
* **Retries & timeouts** live in `NodePolicy`. Exponential backoff, timeout enforcement,
|
|
237
|
+
and structured retry events are exercised heavily in the core test suite.
|
|
238
|
+
|
|
239
|
+
### Metadata & observability
|
|
240
|
+
|
|
241
|
+
Every `Message` carries a mutable `meta` dictionary so nodes can propagate debugging
|
|
242
|
+
breadcrumbs, billing information, or routing hints without touching the payload. The
|
|
243
|
+
runtime clones metadata during streaming and playbook calls (`tests/test_metadata.py`).
|
|
244
|
+
Structured runtime events surface through `FlowEvent` objects; attach middlewares for
|
|
245
|
+
custom logging or metrics ingestion (`examples/mlflow_metrics/`).
|
|
246
|
+
|
|
247
|
+
### Routing & dynamic policies
|
|
248
|
+
|
|
249
|
+
Branching flows stay flexible thanks to routers and optional policies. The
|
|
250
|
+
`predicate_router` and `union_router` helpers can consult a `RoutingPolicy` at runtime to
|
|
251
|
+
override or drop successors, while `DictRoutingPolicy` provides a config-driven
|
|
252
|
+
implementation ready for JSON/YAML/env inputs (`tests/test_routing_policy.py`,
|
|
253
|
+
`examples/routing_policy/`).
|
|
254
|
+
|
|
255
|
+
### Traceable exceptions
|
|
256
|
+
|
|
257
|
+
When retries are exhausted or timeouts fire, PenguiFlow wraps the failure in a
|
|
258
|
+
`FlowError` that preserves the trace id, node metadata, and a stable error code.
|
|
259
|
+
Opt into `emit_errors_to_rookery=True` to receive these objects directly from
|
|
260
|
+
`flow.fetch()`—see `tests/test_errors.py` and `examples/traceable_errors/` for usage.
|
|
261
|
+
|
|
262
|
+
### FlowTestKit
|
|
263
|
+
|
|
264
|
+
The new `penguiflow.testkit` module keeps unit tests tiny:
|
|
265
|
+
|
|
266
|
+
* `await testkit.run_one(flow, message)` boots a flow, emits a message, captures runtime
|
|
267
|
+
events, and returns the first Rookery payload.
|
|
268
|
+
* `testkit.assert_node_sequence(trace_id, [...])` asserts the order in which nodes ran.
|
|
269
|
+
* `testkit.simulate_error(...)` builds coroutine helpers that fail a configurable number
|
|
270
|
+
of times—perfect for retry scenarios.
|
|
271
|
+
|
|
272
|
+
The harness is covered by `tests/test_testkit.py` and demonstrated in
|
|
273
|
+
`examples/testkit_demo/`.
|
|
274
|
+
|
|
182
275
|
|
|
183
276
|
## 🧭 Repo Structure
|
|
184
277
|
|
|
185
278
|
penguiflow/
|
|
186
279
|
__init__.py
|
|
187
280
|
core.py # runtime orchestrator, retries, controller helpers, playbooks
|
|
281
|
+
errors.py # FlowError / FlowErrorCode definitions
|
|
188
282
|
node.py
|
|
189
283
|
types.py
|
|
190
284
|
registry.py
|
|
@@ -273,18 +367,46 @@ stitched directly into a flow adjacency list:
|
|
|
273
367
|
|
|
274
368
|
- `map_concurrent(items, worker, max_concurrency=8)` — fan a single message out into
|
|
275
369
|
many in-memory tasks (e.g., batch document enrichment) while respecting a semaphore.
|
|
276
|
-
- `predicate_router(name,
|
|
277
|
-
boolean functions over payload or headers
|
|
278
|
-
|
|
370
|
+
- `predicate_router(name, predicate, policy=None)` — route messages to successor nodes
|
|
371
|
+
based on simple boolean functions over payload or headers, optionally consulting a
|
|
372
|
+
runtime `policy` to override or filter the computed targets. Perfect for guardrails or
|
|
373
|
+
conditional tool invocation without rebuilding the flow.
|
|
279
374
|
- `union_router(name, discriminated_model)` — accept a Pydantic discriminated union and
|
|
280
375
|
forward each variant to the matching typed successor node. Keeps type-safety even when
|
|
281
376
|
multiple schema branches exist.
|
|
282
377
|
- `join_k(name, k)` — aggregate `k` messages per `trace_id` before resuming downstream
|
|
283
378
|
work. Useful for fan-out/fan-in batching, map-reduce style summarization, or consensus.
|
|
379
|
+
- `DictRoutingPolicy(mapping, key_getter=None)` — load routing overrides from
|
|
380
|
+
configuration and pair it with the router helpers via `policy=...` to switch routing at
|
|
381
|
+
runtime without modifying the flow graph.
|
|
284
382
|
|
|
285
383
|
All helpers are regular `Node` instances under the hood, so they inherit retries,
|
|
286
384
|
timeouts, and validation just like hand-written nodes.
|
|
287
385
|
|
|
386
|
+
### Streaming Responses
|
|
387
|
+
|
|
388
|
+
PenguiFlow now supports **LLM-style streaming** with the `StreamChunk` model. Each
|
|
389
|
+
chunk carries `stream_id`, `seq`, `text`, optional `meta`, and a `done` flag. Use
|
|
390
|
+
`Context.emit_chunk(parent=message, text=..., done=...)` inside a node (or the
|
|
391
|
+
convenience wrapper `await flow.emit_chunk(...)` from outside a node) to push
|
|
392
|
+
chunks downstream without manually crafting `Message` envelopes:
|
|
393
|
+
|
|
394
|
+
```python
|
|
395
|
+
await ctx.emit_chunk(parent=msg, text=token, done=done)
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
- Sequence numbers auto-increment per `stream_id` (defaults to the parent trace).
|
|
399
|
+
- Backpressure is preserved; if the downstream queue is full the helper awaits just
|
|
400
|
+
like `Context.emit`.
|
|
401
|
+
- When `done=True`, the sequence counter resets so a new stream can reuse the same id.
|
|
402
|
+
|
|
403
|
+
Pair the producer with a sink node that consumes `StreamChunk` payloads and assembles
|
|
404
|
+
the final result when `done` is observed. See `examples/streaming_llm/` for a complete
|
|
405
|
+
mock LLM → SSE pipeline. For presentation layers, utilities like
|
|
406
|
+
`format_sse_event(chunk)` and `chunk_to_ws_json(chunk)` (both exported from the
|
|
407
|
+
package) will convert a `StreamChunk` into SSE-compatible text or WebSocket JSON payloads
|
|
408
|
+
without boilerplate.
|
|
409
|
+
|
|
288
410
|
### Dynamic Controller Loops
|
|
289
411
|
|
|
290
412
|
Long-running agents often need to **think, plan, and act over multiple hops**. PenguiFlow
|
|
@@ -306,20 +428,21 @@ easy to surface guardrails to downstream consumers.
|
|
|
306
428
|
### Playbooks & Subflows
|
|
307
429
|
|
|
308
430
|
Sometimes a controller or router needs to execute a **mini flow** — for example,
|
|
309
|
-
retrieval → rerank → compress — without polluting the global topology.
|
|
310
|
-
spawns a brand-new `PenguiFlow` on demand and wires it into
|
|
431
|
+
retrieval → rerank → compress — without polluting the global topology.
|
|
432
|
+
`Context.call_playbook` spawns a brand-new `PenguiFlow` on demand and wires it into
|
|
433
|
+
the parent message context:
|
|
311
434
|
|
|
312
435
|
- Trace IDs and headers are reused so observability stays intact.
|
|
313
|
-
- The helper respects optional timeouts
|
|
436
|
+
- The helper respects optional timeouts, mirrors cancellation to the subflow, and always
|
|
437
|
+
stops it (even on cancel).
|
|
314
438
|
- The first payload emitted to the playbook's Rookery is returned to the caller,
|
|
315
439
|
allowing you to treat subflows as normal async functions.
|
|
316
440
|
|
|
317
441
|
```python
|
|
318
|
-
from penguiflow import call_playbook
|
|
319
442
|
from penguiflow.types import Message
|
|
320
443
|
|
|
321
444
|
async def controller(msg: Message, ctx) -> Message:
|
|
322
|
-
playbook_result = await call_playbook(build_retrieval_playbook, msg)
|
|
445
|
+
playbook_result = await ctx.call_playbook(build_retrieval_playbook, msg)
|
|
323
446
|
return msg.model_copy(update={"payload": playbook_result})
|
|
324
447
|
```
|
|
325
448
|
|
|
@@ -328,12 +451,36 @@ flow focused on high-level orchestration logic.
|
|
|
328
451
|
|
|
329
452
|
---
|
|
330
453
|
|
|
454
|
+
### Visualization
|
|
455
|
+
|
|
456
|
+
Need a quick view of the flow topology? Call `flow_to_mermaid(flow)` to render the graph
|
|
457
|
+
as a Mermaid diagram ready for Markdown or docs tools, or `flow_to_dot(flow)` for a
|
|
458
|
+
Graphviz-friendly definition. Both outputs annotate controller loops and the synthetic
|
|
459
|
+
OpenSea/Rookery boundaries so you can spot ingress/egress paths at a glance:
|
|
460
|
+
|
|
461
|
+
```python
|
|
462
|
+
from penguiflow import flow_to_dot, flow_to_mermaid
|
|
463
|
+
|
|
464
|
+
print(flow_to_mermaid(flow, direction="LR"))
|
|
465
|
+
print(flow_to_dot(flow, rankdir="LR"))
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
See `examples/visualizer/` for a runnable script that exports Markdown and DOT files for
|
|
469
|
+
docs or diagramming pipelines.
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
331
473
|
## 🛡️ Reliability & Observability
|
|
332
474
|
|
|
333
475
|
* **NodePolicy**: set validation scope plus per-node timeout, retries, and backoff curves.
|
|
334
|
-
* **
|
|
335
|
-
|
|
336
|
-
*
|
|
476
|
+
* **Per-trace metrics**: cancellation events include `trace_pending`, `trace_inflight`,
|
|
477
|
+
`q_depth_in`, `q_depth_out`, and node fan-out counts for richer observability.
|
|
478
|
+
* **Structured `FlowEvent`s**: every node event carries `{ts, trace_id, node_name, event,
|
|
479
|
+
latency_ms, q_depth_in, q_depth_out, attempt}` plus a mutable `extra` map for custom
|
|
480
|
+
annotations.
|
|
481
|
+
* **Middleware hooks**: subscribe observers (e.g., MLflow) to the structured `FlowEvent`
|
|
482
|
+
stream. See `examples/mlflow_metrics/` for an MLflow integration and
|
|
483
|
+
`examples/reliability_middleware/` for a concrete timeout + retry walkthrough.
|
|
337
484
|
|
|
338
485
|
---
|
|
339
486
|
|
|
@@ -341,15 +488,25 @@ flow focused on high-level orchestration logic.
|
|
|
341
488
|
|
|
342
489
|
- **In-process runtime**: there is no built-in distribution layer yet. Long-running CPU work should be delegated to your own pools or services.
|
|
343
490
|
- **Registry-driven typing**: nodes default to validation. Provide a `ModelRegistry` when calling `flow.run(...)` or set `validate="none"` explicitly for untyped hops.
|
|
344
|
-
- **Observability**: structured
|
|
345
|
-
-
|
|
491
|
+
- **Observability**: structured `FlowEvent` callbacks power logs/metrics; integrations with
|
|
492
|
+
third-party stacks (OTel, Prometheus, Datadog) remain DIY. See the MLflow middleware
|
|
493
|
+
example for a lightweight pattern.
|
|
494
|
+
- **Roadmap**: follow-up releases focus on optional distributed backends, deeper observability integrations, and additional playbook patterns. Contributions and proposals are welcome!
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## 📊 Benchmarks
|
|
499
|
+
|
|
500
|
+
Lightweight benchmarks live under `benchmarks/`. Run them via `uv run python benchmarks/<name>.py`
|
|
501
|
+
to capture baselines for fan-out throughput, retry/timeout overhead, and controller
|
|
502
|
+
playbook latency. Copy them into product repos to watch for regressions over time.
|
|
346
503
|
|
|
347
504
|
---
|
|
348
505
|
|
|
349
506
|
## 🔮 Roadmap
|
|
350
507
|
|
|
351
|
-
* **
|
|
352
|
-
* **
|
|
508
|
+
* **v2 (current)**: streaming, per-trace cancellation, deadlines/budgets, metadata propagation, observability hooks, visualizer, routing policies, traceable errors, and FlowTestKit.
|
|
509
|
+
* **Future**: optional distributed runners, richer third-party observability adapters, and opinionated playbook templates.
|
|
353
510
|
|
|
354
511
|
---
|
|
355
512
|
|
|
@@ -383,7 +540,12 @@ pytest -q
|
|
|
383
540
|
* `examples/map_concurrent/`: bounded fan-out work inside a node.
|
|
384
541
|
* `examples/controller_multihop/`: dynamic multi-hop agent loop.
|
|
385
542
|
* `examples/reliability_middleware/`: retries, timeouts, and middleware hooks.
|
|
543
|
+
* `examples/mlflow_metrics/`: structured `FlowEvent` export to MLflow (stdout fallback).
|
|
386
544
|
* `examples/playbook_retrieval/`: retrieval → rerank → compress playbook.
|
|
545
|
+
* `examples/trace_cancel/`: per-trace cancellation propagating into a playbook.
|
|
546
|
+
* `examples/streaming_llm/`: mock LLM emitting streaming chunks to an SSE sink.
|
|
547
|
+
* `examples/metadata_propagation/`: attaching and consuming `Message.meta` context.
|
|
548
|
+
* `examples/visualizer/`: exports Mermaid + DOT diagrams with loop/subflow annotations.
|
|
387
549
|
|
|
388
550
|
---
|
|
389
551
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
penguiflow/__init__.py,sha256=AjWRZkwExe3k9nzfcohevh1RbrxXaB71yiSirBBL9eA,1506
|
|
2
|
+
penguiflow/core.py,sha256=cxbkfLNm-dQHPmpSIsvBf0lI7u-xN8-4S-QJhpSr-FU,44698
|
|
3
|
+
penguiflow/errors.py,sha256=mXpCqZ3zdvz7J7Dck_kcw2BGTIm9yrJAjxp_L8KMY7o,3419
|
|
4
|
+
penguiflow/metrics.py,sha256=RW76sYDebzix6Hf7mDemOj-4SwsnILu5YVEoUHNUKuA,3675
|
|
5
|
+
penguiflow/middlewares.py,sha256=4mQgkPowTs6II-_UvIFGyMUTvzhxwDYUicvJMpNNlPU,341
|
|
6
|
+
penguiflow/node.py,sha256=0NOs3rU6t1tHNNwwJopqzM2ufGcp82JpzhckynWBRqs,3563
|
|
7
|
+
penguiflow/patterns.py,sha256=qtzRSNRKxV5_qEPXhffd15PuCZs0YnoGF80nNUsrcxw,5512
|
|
8
|
+
penguiflow/policies.py,sha256=3w8ionnpTyuA0ZCc3jPpB011L7_i1qlbiO6escY024s,4385
|
|
9
|
+
penguiflow/registry.py,sha256=4lrGDMFjM7c8pfZFc_YG0YHg-F80JyF4c-j0UbAf150,1419
|
|
10
|
+
penguiflow/streaming.py,sha256=RKMm4VfaDA2ceEM_pB2Cuhmpwtdcjj7og-kjXQQDcbc,3863
|
|
11
|
+
penguiflow/testkit.py,sha256=wNPqLldHjoq6q7RItSEdKLveSHqXkNj1HAS_FTZDxxs,8581
|
|
12
|
+
penguiflow/types.py,sha256=Fl56-b7OwIEUbPMDD1CY09nbOG_tmBw3FUhioojeG5M,1503
|
|
13
|
+
penguiflow/viz.py,sha256=KbBb9kKoL223vj0NgJV_jo5ny-0RTc2gcSBACm0jG8w,5508
|
|
14
|
+
penguiflow-2.0.0.dist-info/licenses/LICENSE,sha256=JSvodvLXxSct_kI9IBsZOBpVKoESQTB_AGbkClwZ7HI,1065
|
|
15
|
+
penguiflow-2.0.0.dist-info/METADATA,sha256=ogvnFlcFv7X7hHg-piiDENR8SomufxGwh5wiigyWilo,21269
|
|
16
|
+
penguiflow-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
17
|
+
penguiflow-2.0.0.dist-info/top_level.txt,sha256=F-5jgzPP4Mo_ErgtzGDFJdRT4CIfFjFBnxxcn-RpWBU,11
|
|
18
|
+
penguiflow-2.0.0.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
penguiflow/__init__.py,sha256=BIBAYJZtOHQ7AZMBWD0g7d1RTCR9qWLQGwcUuKa5GMo,874
|
|
2
|
-
penguiflow/core.py,sha256=fO5GXF7Hih-gEcUPbyXVJilgUmwbvd72j337r5oOWME,20908
|
|
3
|
-
penguiflow/middlewares.py,sha256=LUlK4FrMScK3oaNSrAYNw3s4KcAZ716DTLAUqvsOkL8,319
|
|
4
|
-
penguiflow/node.py,sha256=0NOs3rU6t1tHNNwwJopqzM2ufGcp82JpzhckynWBRqs,3563
|
|
5
|
-
penguiflow/patterns.py,sha256=Ivuuy0on0OMsdYd5DRFZm1EgujXKPEaIIMH0ZWlJ1s0,4199
|
|
6
|
-
penguiflow/registry.py,sha256=4lrGDMFjM7c8pfZFc_YG0YHg-F80JyF4c-j0UbAf150,1419
|
|
7
|
-
penguiflow/types.py,sha256=QV2JvB_QnohfBATSaviPWm0HSR9B6dTc3UOwFIYyaqg,1154
|
|
8
|
-
penguiflow/viz.py,sha256=_puIEJevq2DrfNuydm3DG1V1o4PgICxd5pA-Es_IyWY,112
|
|
9
|
-
penguiflow-1.0.2.dist-info/licenses/LICENSE,sha256=JSvodvLXxSct_kI9IBsZOBpVKoESQTB_AGbkClwZ7HI,1065
|
|
10
|
-
penguiflow-1.0.2.dist-info/METADATA,sha256=SBuhdqSVKIwo9_vVV2bW2IsmGiia84q59ESqHl8zgR0,13090
|
|
11
|
-
penguiflow-1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
-
penguiflow-1.0.2.dist-info/top_level.txt,sha256=F-5jgzPP4Mo_ErgtzGDFJdRT4CIfFjFBnxxcn-RpWBU,11
|
|
13
|
-
penguiflow-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|