Tubing is a Python I/O library. What makes tubing so freakin’ cool is the gross abuse of the bitwise OR operator (|). Have you ever been writing python code and thought to yourself, “Man, this is great, but I really wish it was a little more like bash.” Welp, we’ve made python a little more like bash.If you are a super lame nerd-kid, you can replace any of the bitwise ORs with the pipe() function and pray we don’t overload any other operators in future versions. If you do avoid the bitwise OR, we don’t know if we want to hang out with you.
Tubing is pretty bare-bones at the moment. We’ve tried to make it easy to add your own functionality. Hopefully you find it not all that unpleasant. There are three sections below for adding sources, pipes and sink. If you do make some additions, think about committing them back upstream. We’d love to have a full suite of tools.
Now for an example to show the true power of this fully operational I/O library:
from tubing import sources, pipes, sinks
objs = [
dict(
name="Bob Corsaro",
birthdate="08/03/1977",
alignment="evil",
),
dict(
name="Tom Brady",
birthdate="08/03/1977",
alignment="good",
),
]
sources.Objects(objs) \
| pipes.JSONSerializer() \
| pipes.Joined(by=b"\n") \
| pipes.Gzip() \
| sinks.File("output.gz", "wb")
Then in our old friend bash:
$ zcat output.gz
{"alignment": "evil", "birthdate": "08/03/1977", "name": "Bob Corsaro"}
{"alignment": "good", "birthdate": "08/03/1977", "name": "Tom Brady"}
$
We need to seriously think about renaming pipes to tubes.. man, what was I thinking?
Sources
To make your own source, create a Reader class with the following interface:
class MyReader(object):
"""
MyReader returns count instances of data.
"""
def __init__(self, data="hello world\n", count=10):
self.data = data
self.count = count
def read(self, amt):
"""
read(amt) returns $amt of data and a boolean indicating EOF.
"""
if not amt:
amt = self.count
r = self.data * min(amt, self.count)
self.count -= amt
return r, self.count <= 0
The important thing to remember is that your read function should return an iterable of units of data, not a single piece of data. Then wrap your reader in the loving embrace of MakeSource:
from tubing import sources MySource = sources.MakeSource(MyReader)
Now it can be used in a pipeline!:
from __future__ import print_function
from tubing import pipes
sink = MySource(data="goodbye cruel world!", count=1) \
| pipes.Joined(by=b"\n") \
| sinks.Bytes()
print(sinks.result)
# Output: goodby cruel world!
Pipes
Making your own pipe is a lot more fun, trust me. First make a Transformer:
class OptimusPrime(object):
def transform(self, chunk):
return list(reversed(chunk))
chunk is an iterable with a len() of whatever type of data the stream is working with. In Transformers, you don’t need to worry about buffer size or closing or exception, just transform an iterable to another iterable. There are lots of examples in pipes.py.
Next give Optimus Prime a hug:
from tubing import pipes AllMixedUp = pipes.MakePipe(OptimusPrime)
Ready to mix up some data?:
from __future__ import print_function
import json
from tubing import sources, sinks
objs = [{"number": i} for i in range(0, 10)]
sink = sources.Objects(objs) \
| AllMixedUp(chunk_size=2) \
| sinks.Objects()
print(json.dumps(sink))
# Output: [{"number": 1}, {"number": 0}, {"number": 3}, {"number": 2}, {"number": 5}, {"number": 4}, {"number": 7}, {"number": 6}, {"number": 9}, {"number": 8}]
Sinks
Really getting tired of making documentation… Maybe I’ll finish later. I have real work to do.
Well.. I’m this far, let’s just push through:
from __future__ import print_function
from tubing import sources, pipes, sinks
class StdoutWriter(object):
def write(self, chunk):
for part in chunk:
print(part)
def close(self):
# this function is optional
print("That's all folks!")
def abort(self):
# this is also optional
print("Something terrible has occurred.")
Debugger = sinks.MakeSink(StdoutWriter)
objs = [{"number": i} for i in range(0, 10)]
sink = sources.Objects(objs) \
| AllMixedUp(chunk_size=2) \
| pipes.JSONSerializer() \
| pipes.Joined(by=b"\n") \
| Debugger()
# Output:
#{"number": 1}
#{"number": 0}
#{"number": 3}
#{"number": 2}
#{"number": 5}
#{"number": 4}
#{"number": 7}
#{"number": 6}
#{"number": 9}
#{"number": 8}
#That's all folks!
Metadata
Release files for tubing 0.0.2.post98
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tubing-0.0.2.post98.tar.gz | 9.8 kB | Without provenance | Details for tubing-0.0.2.post98.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tubing-0.0.2.post98-py2.py3-none-any.whl | Python 2, Python 3 | none | any | Details for tubing-0.0.2.post98-py2.py3-none-any.whl |
Total release size: 23.4 kB
Release files / tubing-0.0.2.post98.tar.gz
| Download URL | tubing-0.0.2.post98.tar.gz |
|---|---|
| Size | 9.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fe3a95d0875e05263bb54d36a087e1c5e30da4b5106f39c933dd3c45d5e1fe34
|
|
BLAKE2b-256 checksum How to use checksums |
0ad672614991e691a51c5e2ad8db26a051cd51a7b0193ed5026d56e026a513de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Release files / tubing-0.0.2.post98-py2.py3-none-any.whl
| Download URL | tubing-0.0.2.post98-py2.py3-none-any.whl |
|---|---|
| Size | 13.5 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
6825ea827727bbbd3a96c54f54d5c66b248b740881ede467601ae5a4c7d29537
|
|
BLAKE2b-256 checksum How to use checksums |
7f7965748da5ad8dbfeba19774a79aa0d085c95807e448bfcb7316f79c5a3b9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Security for tubing 0.0.2.post98
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.