Port70: Async Gopher Protocol Client Library
Port70 is an async-first, fully type-hinted Python client library for the Gopher protocol (RFC 1436 / RFC 4266).
Features
- Async First: Built on top of Python's standard
asyncionetworking loop. - RFC 1436 & RFC 4266 Support: Full support for standard Gopher item types, selectors, search queries, and URIs.
- Type Safe: Fully typed API passing strict static type checking (
mypy --strict). - GopherURI Representation: Rich URI class to parse, inspect, validate, manipulate, and resolve Gopher URIs and query targets.
- Zero Dependencies: Built entirely on Python's standard library.
- CLI Utility: Includes a
port70command-line interface out of the box.
Installation
port70 requires Python 3.12 or later and can be installed with your package manager of choice.
With pip:
pip install port70
With uv:
uv add port70
Quick Start
1. Make a Simple Request
Use Client with standard async context managers to query a Gopher server:
import asyncio
from port70 import Client, Port70Error
async def main():
async with Client() as client:
try:
# Query a Gopher menu or document
response = await client.request("gopher://gopher.floodgap.com/")
print(f"Target host: {response.uri.host}")
print(f"Item type: {response.item_type}")
print(f"Content length: {len(response.content)} bytes")
print("--- Response Text ---")
print(response.text)
except Port70Error as error:
print(f"Request failed: {error}")
if __name__ == "__main__":
asyncio.run(main())
2. Working with GopherURI
The GopherURI class parses both full URI strings (gopher://host/1/selector) and target format strings:
from port70 import GopherURI
# Parse from Gopher URI string
uri = GopherURI.from_string("gopher://gopher.floodgap.com/7/v2/vs?python")
print(uri.host) # 'gopher.floodgap.com'
print(uri.port) # 70
print(uri.item_type) # '7'
print(uri.selector) # '/v2/vs'
print(uri.query) # 'python'
print(uri.is_search) # True
# Create modified copies
custom_port_uri = uri.with_port(7070)
parent_uri = uri.parent
root_uri = uri.root
3. Search Queries and Response Inspection
You can issue search queries for item type 7 search engines or inspect item types on responses:
async with Client() as client:
# Send a search request with query terms
response = await client.request(
"gopher://gopher.floodgap.com/7/v2/vs",
query_terms="python",
)
assert response.is_text
# Access text response split into lines
for line in response.lines[:5]:
print(line)
Command Line Interface (CLI)
port70 includes a command-line client:
# Query a Gopher target (defaults to gopher://gopher.floodgap.com/)
uv run port70 gopher://gopher.floodgap.com/
# Perform a search request
uv run port70 -q python gopher://gopher.floodgap.com/7/v2/vs
# Query on a custom port
uv run port70 -p 7070 gopher://example.com/1/
# Output raw binary content to stdout
uv run port70 -r gopher://gopher.floodgap.com/0/gopher/readdata
# Display CLI help
uv run port70 --help
Licence
MIT
Metadata
Release files for port70 1.0.0
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 |
|---|---|---|---|---|
| port70-1.0.0.tar.gz | 9.5 kB | Without provenance | Details for port70-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| port70-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for port70-1.0.0-py3-none-any.whl |
Total release size: 21.3 kB
Release files / port70-1.0.0.tar.gz
| Download URL | port70-1.0.0.tar.gz |
|---|---|
| Size | 9.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c5f58df5c7f1d6f42d95e4456e9878357b3d8827d7c7a377045ba529043cc050
|
|
BLAKE2b-256 checksum How to use checksums |
a0fccd64e080aee9887618105bb414cf56e71c0b745cc421f0e12c49a7fd0373
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / port70-1.0.0-py3-none-any.whl
| Download URL | port70-1.0.0-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ac956e27d62502687442823371ade772895b7992918d03978ca8bed157b497f4
|
|
BLAKE2b-256 checksum How to use checksums |
e5614ef6a612b4f8cce8cb36a4e9a801077d94b2d017448626c3fd07f4ccddb6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for port70 1.0.0
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.