gophermap 0.0.1__tar.gz → 0.0.2__tar.gz
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.
- gophermap-0.0.2/PKG-INFO +49 -0
- gophermap-0.0.2/README.md +23 -0
- gophermap-0.0.2/pyproject.toml +111 -0
- gophermap-0.0.2/src/gophermap/__init__.py +34 -0
- gophermap-0.0.2/src/gophermap/__main__.py +25 -0
- gophermap-0.0.2/src/gophermap/exceptions.py +14 -0
- gophermap-0.0.2/src/gophermap/gopher_map.py +57 -0
- gophermap-0.0.2/src/gophermap/item.py +75 -0
- gophermap-0.0.2/src/gophermap/item_type.py +69 -0
- gophermap-0.0.1/PKG-INFO +0 -9
- gophermap-0.0.1/README.md +0 -0
- gophermap-0.0.1/pyproject.toml +0 -23
- gophermap-0.0.1/src/gophermap/__init__.py +0 -2
gophermap-0.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gophermap
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: A simple library for parsng Gophermaps
|
|
5
|
+
Keywords: Gopher,Gophermap,Hypertext,library,Markup,parser,Small Web,smolweb
|
|
6
|
+
Author: Dave Pearson
|
|
7
|
+
Author-email: Dave Pearson <davep@davep.org>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Project-URL: Homepage, https://gophermap.davep.dev/
|
|
20
|
+
Project-URL: Repository, https://github.com/davep/gophermap
|
|
21
|
+
Project-URL: Documentation, https://gophermap.davep.dev/
|
|
22
|
+
Project-URL: Source, https://github.com/davep/gophermap
|
|
23
|
+
Project-URL: Issues, https://github.com/davep/gophermap/issues
|
|
24
|
+
Project-URL: Discussions, https://github.com/davep/gophermap/discussions
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# gophermap - A simple library for parsing Gopher maps
|
|
28
|
+
|
|
29
|
+
`gophermap` is a small and simple library that provides code for parsing
|
|
30
|
+
Gopher responses.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
`gophermap` is [available from pypi](https://pypi.org/project/gophermap/)
|
|
35
|
+
and can be installed with your package installer of choice.
|
|
36
|
+
|
|
37
|
+
With `pip`:
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
pip install gophermap
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
With `uv`:
|
|
44
|
+
|
|
45
|
+
```shell
|
|
46
|
+
uv add gophermap
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
[//]: # (README.md ends here)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# gophermap - A simple library for parsing Gopher maps
|
|
2
|
+
|
|
3
|
+
`gophermap` is a small and simple library that provides code for parsing
|
|
4
|
+
Gopher responses.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
`gophermap` is [available from pypi](https://pypi.org/project/gophermap/)
|
|
9
|
+
and can be installed with your package installer of choice.
|
|
10
|
+
|
|
11
|
+
With `pip`:
|
|
12
|
+
|
|
13
|
+
```shell
|
|
14
|
+
pip install gophermap
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
With `uv`:
|
|
18
|
+
|
|
19
|
+
```shell
|
|
20
|
+
uv add gophermap
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
[//]: # (README.md ends here)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "gophermap"
|
|
3
|
+
version = "0.0.2"
|
|
4
|
+
description = "A simple library for parsng Gophermaps"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Dave Pearson", email = "davep@davep.org" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = []
|
|
11
|
+
license = "MIT"
|
|
12
|
+
keywords = [
|
|
13
|
+
"Gopher",
|
|
14
|
+
"Gophermap",
|
|
15
|
+
"Hypertext",
|
|
16
|
+
"library",
|
|
17
|
+
"Markup",
|
|
18
|
+
"parser",
|
|
19
|
+
"Small Web",
|
|
20
|
+
"smolweb",
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Development Status :: 3 - Alpha",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
30
|
+
"Topic :: Software Development :: Libraries",
|
|
31
|
+
"Typing :: Typed",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://gophermap.davep.dev/"
|
|
36
|
+
Repository = "https://github.com/davep/gophermap"
|
|
37
|
+
Documentation = "https://gophermap.davep.dev/"
|
|
38
|
+
Source = "https://github.com/davep/gophermap"
|
|
39
|
+
Issues = "https://github.com/davep/gophermap/issues"
|
|
40
|
+
Discussions = "https://github.com/davep/gophermap/discussions"
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
gophermap = "gophermap.__main__:parse_input"
|
|
44
|
+
|
|
45
|
+
[build-system]
|
|
46
|
+
requires = ["uv_build>=0.11.32,<0.12.0"]
|
|
47
|
+
build-backend = "uv_build"
|
|
48
|
+
|
|
49
|
+
[[tool.uv.index]]
|
|
50
|
+
name = "testpypi"
|
|
51
|
+
url = "https://test.pypi.org/simple/"
|
|
52
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
53
|
+
explicit = true
|
|
54
|
+
|
|
55
|
+
[tool.pyright]
|
|
56
|
+
venvPath="."
|
|
57
|
+
venv=".venv"
|
|
58
|
+
exclude=[".venv"]
|
|
59
|
+
|
|
60
|
+
[dependency-groups]
|
|
61
|
+
dev = [
|
|
62
|
+
"codespell>=2.4.3",
|
|
63
|
+
"mypy>=2.3.0",
|
|
64
|
+
"pre-commit>=4.6.0",
|
|
65
|
+
"ruff>=0.15.22",
|
|
66
|
+
]
|
|
67
|
+
docs = [
|
|
68
|
+
"mkdocs>=1.6.1,<2",
|
|
69
|
+
"mkdocs-material>=9.7.6",
|
|
70
|
+
"mkdocstrings[python]>=1.0.4",
|
|
71
|
+
]
|
|
72
|
+
test = [
|
|
73
|
+
"pytest>=9.1.1",
|
|
74
|
+
"pytest-cov>=7.1.0",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint]
|
|
78
|
+
select = [
|
|
79
|
+
# pycodestyle
|
|
80
|
+
"E",
|
|
81
|
+
# Pyflakes
|
|
82
|
+
"F",
|
|
83
|
+
# pyupgrade
|
|
84
|
+
"UP",
|
|
85
|
+
# flake8-bugbear
|
|
86
|
+
"B",
|
|
87
|
+
# flake8-simplify
|
|
88
|
+
"SIM",
|
|
89
|
+
# isort
|
|
90
|
+
"I",
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
[tool.ruff.lint.pycodestyle]
|
|
94
|
+
max-line-length = 120
|
|
95
|
+
|
|
96
|
+
[tool.coverage.run]
|
|
97
|
+
omit = [
|
|
98
|
+
"tests/*"
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
[tool.coverage.report]
|
|
102
|
+
exclude_lines = [
|
|
103
|
+
"pragma: no cover",
|
|
104
|
+
"def __repr__",
|
|
105
|
+
"raise AssertionError",
|
|
106
|
+
"raise NotImplementedError",
|
|
107
|
+
"if __name__ == .__main__.:",
|
|
108
|
+
"if TYPE_CHECKING:",
|
|
109
|
+
"class .*\\bProtocol\\):",
|
|
110
|
+
"@(abc\\.)?abstractmethod",
|
|
111
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Provides tools for working with Gopher maps."""
|
|
2
|
+
|
|
3
|
+
##############################################################################
|
|
4
|
+
# Python imports.
|
|
5
|
+
from importlib.metadata import version
|
|
6
|
+
|
|
7
|
+
######################################################################
|
|
8
|
+
# Main library information.
|
|
9
|
+
__author__ = "Dave Pearson"
|
|
10
|
+
__copyright__ = "Copyright 2026, Dave Pearson"
|
|
11
|
+
__credits__ = ["Dave Pearson"]
|
|
12
|
+
__maintainer__ = "Dave Pearson"
|
|
13
|
+
__email__ = "davep@davep.org"
|
|
14
|
+
__version__: str = version("gophermap")
|
|
15
|
+
__licence__ = "MIT"
|
|
16
|
+
|
|
17
|
+
##############################################################################
|
|
18
|
+
# Local imports.
|
|
19
|
+
from .exceptions import GopherMapError, NoFields
|
|
20
|
+
from .gopher_map import GopherMap
|
|
21
|
+
from .item import GopherItem
|
|
22
|
+
from .item_type import ItemType
|
|
23
|
+
|
|
24
|
+
##############################################################################
|
|
25
|
+
# Exports.
|
|
26
|
+
__all__ = [
|
|
27
|
+
"GopherItem",
|
|
28
|
+
"GopherMap",
|
|
29
|
+
"GopherMapError",
|
|
30
|
+
"ItemType",
|
|
31
|
+
"NoFields",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
### __init__.py ends here
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""A simple parser to show how the library works."""
|
|
2
|
+
|
|
3
|
+
##############################################################################
|
|
4
|
+
# Python imports.
|
|
5
|
+
import fileinput
|
|
6
|
+
|
|
7
|
+
##############################################################################
|
|
8
|
+
# Local imports.
|
|
9
|
+
from gophermap import GopherMap
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##############################################################################
|
|
13
|
+
def parse_input() -> None:
|
|
14
|
+
"""Parse the input from stdin or files and print the parsed Gopher map."""
|
|
15
|
+
with fileinput.input() as gopher_map:
|
|
16
|
+
for gopher_item in GopherMap("".join(gopher_map)).items:
|
|
17
|
+
print(f"{gopher_item!r}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
##############################################################################
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
parse_input()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### __main__.py ends here
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Exceptions for the library."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
##############################################################################
|
|
5
|
+
class GopherMapError(Exception):
|
|
6
|
+
"""Base exception for all errors raised by the GopherMap library."""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
##############################################################################
|
|
10
|
+
class NoFields(GopherMapError):
|
|
11
|
+
"""Raised when a Gopher item has no fields."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### exceptions.py ends here
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Provides a class for parsing and holding a Gopher map."""
|
|
2
|
+
|
|
3
|
+
##############################################################################
|
|
4
|
+
# Python imports.
|
|
5
|
+
from collections.abc import Iterator
|
|
6
|
+
from functools import cached_property
|
|
7
|
+
from typing import Final
|
|
8
|
+
|
|
9
|
+
##############################################################################
|
|
10
|
+
# Local imports.
|
|
11
|
+
from .item import GopherItem
|
|
12
|
+
|
|
13
|
+
##############################################################################
|
|
14
|
+
EOF: Final = ".\r\n"
|
|
15
|
+
"""The EOF marker for a Gopher map."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
##############################################################################
|
|
19
|
+
class GopherMap:
|
|
20
|
+
"""A class for parsing and holding a Gopher map."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, map_text: str) -> None:
|
|
23
|
+
"""Initialise the Gopher map.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
map_text: The text of the Gopher map.
|
|
27
|
+
"""
|
|
28
|
+
self._raw = map_text
|
|
29
|
+
"""The raw text of the Gopher map."""
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def _parse_map(map_text: str) -> Iterator[GopherItem]:
|
|
33
|
+
"""Parse the Gopher map text into a list of Gopher items.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
map_text: The text of the Gopher map.
|
|
37
|
+
|
|
38
|
+
Yields:
|
|
39
|
+
Gopher items.
|
|
40
|
+
"""
|
|
41
|
+
for line in map_text.splitlines(keepends=True):
|
|
42
|
+
if line == EOF:
|
|
43
|
+
break
|
|
44
|
+
yield GopherItem(line)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def raw(self) -> str:
|
|
48
|
+
"""The raw text of the Gopher map."""
|
|
49
|
+
return self._raw
|
|
50
|
+
|
|
51
|
+
@cached_property
|
|
52
|
+
def items(self) -> tuple[GopherItem, ...]:
|
|
53
|
+
"""The list of Gopher items in the map."""
|
|
54
|
+
return tuple(self._parse_map(self._raw))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### gopher_map.py ends here
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Provides a class for holding an item in the Gopher map."""
|
|
2
|
+
|
|
3
|
+
##############################################################################
|
|
4
|
+
# Local imports.
|
|
5
|
+
from .exceptions import NoFields
|
|
6
|
+
from .item_type import ItemType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
##############################################################################
|
|
10
|
+
class GopherItem:
|
|
11
|
+
"""A class for holding an item in the Gopher map."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, line: str) -> None:
|
|
14
|
+
"""Initialise the Gopher item.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
line: The line of text from the Gopher map.
|
|
18
|
+
"""
|
|
19
|
+
if not line:
|
|
20
|
+
raise NoFields("The Gopher item line is empty.")
|
|
21
|
+
if "\t" not in line:
|
|
22
|
+
raise NoFields(f"The Gopher item line has no tab characters: {line!r}")
|
|
23
|
+
self._raw = line
|
|
24
|
+
"""The raw text of the Gopher item."""
|
|
25
|
+
fields = line.rstrip("\r\n").split("\t")
|
|
26
|
+
self._type = ItemType(fields[0][0] or ItemType.INFO)
|
|
27
|
+
"""The type of the Gopher item."""
|
|
28
|
+
self._display_text = fields[0][1:] if len(fields) > 0 else ""
|
|
29
|
+
"""The display text of the Gopher item."""
|
|
30
|
+
self._selector = fields[1] if len(fields) > 1 else ""
|
|
31
|
+
"""The selector of the Gopher item."""
|
|
32
|
+
self._host = fields[2] if len(fields) > 2 else ""
|
|
33
|
+
"""The host of the Gopher item."""
|
|
34
|
+
self._port = int(fields[3]) if len(fields) > 3 and fields[3].isdigit() else 70
|
|
35
|
+
"""The port of the Gopher item."""
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def raw(self) -> str:
|
|
39
|
+
"""The raw text of the Gopher item."""
|
|
40
|
+
return self._raw
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def type(self) -> ItemType:
|
|
44
|
+
"""The type of the Gopher item."""
|
|
45
|
+
return self._type
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def display_text(self) -> str:
|
|
49
|
+
"""The display text of the Gopher item."""
|
|
50
|
+
return self._display_text
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def selector(self) -> str:
|
|
54
|
+
"""The selector of the Gopher item."""
|
|
55
|
+
return self._selector
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def host(self) -> str:
|
|
59
|
+
"""The host of the Gopher item."""
|
|
60
|
+
return self._host
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def port(self) -> int:
|
|
64
|
+
"""The port of the Gopher item."""
|
|
65
|
+
return self._port
|
|
66
|
+
|
|
67
|
+
def __repr__(self) -> str:
|
|
68
|
+
"""Return a string representation of the Gopher item."""
|
|
69
|
+
return (
|
|
70
|
+
f"GopherItem(type={self.type!r}, display_text={self.display_text!r}, "
|
|
71
|
+
f"selector={self.selector!r}, host={self.host!r}, port={self.port!r})"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### item.py ends here
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Provides an enumeration for the different types of Gopher items."""
|
|
2
|
+
|
|
3
|
+
##############################################################################
|
|
4
|
+
# Future imports.
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
##############################################################################
|
|
8
|
+
# Python imports.
|
|
9
|
+
from enum import StrEnum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##############################################################################
|
|
13
|
+
class ItemType(StrEnum):
|
|
14
|
+
"""An enumeration for the different types of Gopher items."""
|
|
15
|
+
|
|
16
|
+
TEXT = "0"
|
|
17
|
+
"""A text file."""
|
|
18
|
+
MENU = "1"
|
|
19
|
+
"""A menu."""
|
|
20
|
+
CSO = "2"
|
|
21
|
+
"""A CSO phone book."""
|
|
22
|
+
ERROR = "3"
|
|
23
|
+
"""An error message."""
|
|
24
|
+
BINHEX = "4"
|
|
25
|
+
"""A BinHexed file."""
|
|
26
|
+
DOS_FILE = "5"
|
|
27
|
+
"""A DOS file."""
|
|
28
|
+
UUENCODED = "6"
|
|
29
|
+
"""A uuencoded file."""
|
|
30
|
+
INDEX_SEARCH = "7"
|
|
31
|
+
"""An index search."""
|
|
32
|
+
TELNET = "8"
|
|
33
|
+
"""A telnet session."""
|
|
34
|
+
BINARY = "9"
|
|
35
|
+
"""A binary file."""
|
|
36
|
+
INFO = "i"
|
|
37
|
+
"""An informational message."""
|
|
38
|
+
GIF = "g"
|
|
39
|
+
"""A GIF image."""
|
|
40
|
+
IMAGE = "I"
|
|
41
|
+
"""An image file."""
|
|
42
|
+
HTML = "h"
|
|
43
|
+
"""An HTML file."""
|
|
44
|
+
DOCUMENT = "d"
|
|
45
|
+
"""A document file."""
|
|
46
|
+
AUDIO = "s"
|
|
47
|
+
"""An audio file."""
|
|
48
|
+
PDF = "P"
|
|
49
|
+
"""A PDF file."""
|
|
50
|
+
XML = "X"
|
|
51
|
+
"""An XML file."""
|
|
52
|
+
UNKNOWN = "unknown"
|
|
53
|
+
"""An unknown type."""
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def _missing_(cls, value: object) -> ItemType:
|
|
57
|
+
"""Handle missing values in the enumeration.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
value: The value that is missing.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
The corresponding ItemType for the missing value.
|
|
64
|
+
"""
|
|
65
|
+
assert isinstance(value, str)
|
|
66
|
+
return ItemType.UNKNOWN
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
### item_type.py ends here
|
gophermap-0.0.1/PKG-INFO
DELETED
gophermap-0.0.1/README.md
DELETED
|
File without changes
|
gophermap-0.0.1/pyproject.toml
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "gophermap"
|
|
3
|
-
version = "0.0.1"
|
|
4
|
-
description = "Coming soon"
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
authors = [
|
|
7
|
-
{ name = "Dave Pearson", email = "davep@davep.org" }
|
|
8
|
-
]
|
|
9
|
-
requires-python = ">=3.12"
|
|
10
|
-
dependencies = []
|
|
11
|
-
|
|
12
|
-
[project.scripts]
|
|
13
|
-
gophermap = "gophermap:main"
|
|
14
|
-
|
|
15
|
-
[build-system]
|
|
16
|
-
requires = ["uv_build>=0.11.32,<0.12.0"]
|
|
17
|
-
build-backend = "uv_build"
|
|
18
|
-
|
|
19
|
-
[[tool.uv.index]]
|
|
20
|
-
name = "testpypi"
|
|
21
|
-
url = "https://test.pypi.org/simple/"
|
|
22
|
-
publish-url = "https://test.pypi.org/legacy/"
|
|
23
|
-
explicit = true
|