aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/conf.py18
-rw-r--r--docs/index.rst131
-rw-r--r--src/bbss/lists.py5
3 files changed, 128 insertions, 26 deletions
diff --git a/docs/conf.py b/docs/conf.py
index a851995..760ad19 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -2,7 +2,6 @@ import sys
import pathlib
sys.path.append(str(pathlib.PurePath(__file__).parent.parent.joinpath('src')))
-print(sys.path)
# Configuration file for the Sphinx documentation builder.
@@ -21,15 +20,26 @@ release = '0.1.0'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
-extensions = ['sphinx.ext.autodoc']
+extensions = ['sphinx.ext.doctest', 'sphinx.ext.intersphinx']
templates_path = ['_templates']
exclude_patterns = ['*~']
-autodoc_default_options = { "members": None }
-
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'sphinxdoc'
html_static_path = ['_static']
+
+python_display_short_literal_types = True
+
+intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
+
+doctest_global_setup = """
+import bbss
+import bbss.lists
+import bbss.buttons
+import bbss.friends
+import bbss.site
+import bbss.sizes
+"""
diff --git a/docs/index.rst b/docs/index.rst
index ec56a5d..963c702 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -18,39 +18,128 @@ bbss.site
.. py:module:: bbss.site
-.. py:class:: Site(domain: str[, path: str[, *, scheme: str = 'https']])
+ .. py:class:: Site(domain, path, *, scheme = 'https')
- `domain`
- The domain to check for BBSS files
+ A representation of some BBSS directory. On construction, all information about an individual site
+ is downloaded.
- `path`
- An optional subdirectory to treat as the root of the BBSS directory
+ :param str domain: The domain to check for BBSS files
- `scheme`
- What protocol to download over; can be either :python:`'http'` or :python:`'https'`
+ :param path: An optional subdirectory to treat as the root of the BBSS directory
+ :type path: str or None
+ :param scheme: What protocol to download over
+ :type scheme: 'http' | 'https'
- A representation of some BBSS directory. On construction, all information about an individual site
- is downloaded.
+ .. py:attribute:: default_path
+ :type: bool
- .. py:attribute:: default_path
- :type: bool
+ Whether the site was generated from a default directory, or a user-supplied one
- Whether the site was generated from a default directory, or a user-supplied one
+ .. py:attribute:: has_sizes_txt
+ :type: bool
- .. py:attribute:: has_sizes_txt
- :type: bool
+ Whether the BBSS directory contains a ``sizes.txt`` file
- Whether the BBSS directory contains a :code:`sizes.txt` file
+ .. py:attribute:: sizes
+ :type: bbss.sizes.SizeListFile
- .. py:attribute:: sizes
- :type: bbss.sizes.SizeListFile
+ A list of the sizes found at the site
- A list of the sizes found at the site
+ .. py:attribute:: friends
+ :type: Optional[bbss.friends.FriendListFile]
- .. py:attribute:: friends
- :type: Optional[bbss.friends.FriendListFile]
+ A list of friend sites found at the site
+
+bbss.lists
+==========
+
+.. py:module:: bbss.lists
+
+ .. py:function:: parse_listfile[T](contents, ctor)
+
+ Parses in the text of a listfile, and calls the passed constructor
+ function repeatedly to generate datastructures.
+
+ :param str contents: The contents of the listfile
+ :param ctor: The constructor for the internal datastructures
+ :type ctor: (str, str or None) -> T
+ :return: A list of T, containing the contents of the file
+ :rtype: list[T]
+
+ .. doctest::
+
+ >>> listfile = """
+ ... entry 1
+ ... ## this is a comment on entry two
+ ... entry 2
+ ... # omitted
+ ... entry 3
+ ... ## trailing comments are ignored
+ ... """
+ >>> bbss.lists.parse_listfile(listfile, lambda x, y: (x, y))
+ [('entry 1', None), ('entry 2', 'this is a comment on entry two'), ('entry 3', None)]
+
+ .. py:class:: ListFileEntry(entry, comment)
+
+ The base class for all listfile entries.
+
+ :param str entry: The main content of the entry
+ :param comment: The comment, if present
+ :type comment: str or None
+
+ .. py:class:: BaseListFile(contents)
+
+ The base class for all listfile representations.
+
+ It supports all the :py:class:`collections.abc.Sequence` operations, meaning it can be used like a list in most cases.
+
+ :param str contents: The contents of the source listfile
+
+ .. py:classmethod:: from_url(url)
+
+ Alternate constructor, which will attempt to download the listfile at ``url``.
+
+ :param str url: The URL to download from.
+ :return: A representation of the remote file, if available
+ :rtype: BaseListFile | None
+
+ .. py:class:: ListFile(contents)
+
+ A representation of an arbitrary listfile.
+
+ It supports all the :py:class:`collections.abc.Sequence` operations, meaning it can be used like a list in most cases.
+
+ :param str contents: The contents of the source listfile
+
+ .. py:classmethod:: from_url(url)
+
+ Alternate constructor, which will attempt to download the listfile at ``url``.
+
+ :param str url: The URL to download from.
+ :return: A representation of the remote file, if available
+ :rtype: BaseListFile | None
+
+ .. doctest::
+
+ >>> contents = """
+ ... entry 1
+ ... ## this is a comment on entry two
+ ... entry 2
+ ... # omitted
+ ... entry 3
+ ... ## trailing comments are ignored
+ ... """
+ >>> listfile = bbss.lists.ListFile(contents)
+ >>> for entry in listfile:
+ ... print(">", entry.entry)
+ ... if entry.comment is not None:
+ ... print(f" ``{entry.comment}''")
+ ...
+ > entry 1
+ > entry 2
+ ``this is a comment on entry two''
+ > entry 3
- A list of friend sites found at the site
==================
Indices and tables
diff --git a/src/bbss/lists.py b/src/bbss/lists.py
index 5bcdddf..6fa757f 100644
--- a/src/bbss/lists.py
+++ b/src/bbss/lists.py
@@ -8,12 +8,15 @@ def parse_listfile(contents: str, ctor: Callable[[str, Optional[str]], T]) -> Li
acc = []
comment_acc = []
for line in contents.splitlines():
- if line.startswith("#"):
+ if not len(line):
continue
elif line.startswith("##"):
comment_acc.append(line[2:].strip())
+ elif line.startswith("#"):
+ continue
else:
acc.append(ctor(line, " ".join(comment_acc) if len(comment_acc) else None))
+ comment_acc = []
return acc
@dataclass(frozen=True)