From db3326aace80b5c98951c6078aea21064b2877ea Mon Sep 17 00:00:00 2001 From: Alex Maldonado Date: Sat, 11 Apr 2026 23:09:33 -0400 Subject: [PATCH] docs: fix autorefs by using fully qualified path --- docs/gen_ref_pages.py | 53 +++++++++++++---------- pcdigitizer/data/dissociation_constant.py | 46 ++++++++++---------- pcdigitizer/pubchem.py | 34 +++++++-------- pcdigitizer/responses.py | 12 ++--- 4 files changed, 77 insertions(+), 68 deletions(-) diff --git a/docs/gen_ref_pages.py b/docs/gen_ref_pages.py index f2f24e4..c39cd5a 100644 --- a/docs/gen_ref_pages.py +++ b/docs/gen_ref_pages.py @@ -1,36 +1,45 @@ -"""Generate the code reference pages.""" +"""Generate code reference pages for mkdocstrings. + +This script is executed by the mkdocs-gen-files plugin during the MkDocs build +process. It walks the source package, creates a corresponding Markdown stub for +each public module, and builds a nav.yml file so that the API reference section +is generated automatically. +""" -import os from pathlib import Path import mkdocs_gen_files +import yaml -SRC_DIR = "pcdigitizer" -WRITE_DIR = "api" +SRC_DIR = Path("pcdigitizer") +DOC_DIR = Path("api") +SKIP_MODULES = {"__main__", "__init__"} +SKIP_PREFIXES = ("_",) -for path in sorted(Path(SRC_DIR).rglob("*.py")): # - module_path = path.relative_to(SRC_DIR).with_suffix("") # +nav_items: list[dict[str, str] | dict[str, list]] = [] - doc_path = path.relative_to(SRC_DIR).with_suffix(".md") # +for path in sorted(SRC_DIR.rglob("*.py")): + module_path = path.relative_to(SRC_DIR).with_suffix("") + doc_path = path.relative_to(SRC_DIR).with_suffix(".md") + full_doc_path = DOC_DIR / doc_path - if not os.path.exists(Path(WRITE_DIR)): - os.mkdir(Path(WRITE_DIR)) + parts = tuple(module_path.parts) - full_doc_path = Path(WRITE_DIR, doc_path) # - - parts = list(module_path.parts) - - if parts[-1] == "__init__": # - parts = parts[:-1] - elif parts[-1] == "__main__": + if not parts: + continue + if parts[-1] in SKIP_MODULES: + continue + if any(part.startswith(prefix) for part in parts for prefix in SKIP_PREFIXES): continue - if len(parts) == 0: - continue + qualified_name = ".".join((SRC_DIR.name, *parts)) - with mkdocs_gen_files.open(full_doc_path, "w") as fd: # - identifier = ".".join(parts) # + nav_items.append({qualified_name: doc_path.as_posix()}) - print("::: " + identifier, file=fd) # + with mkdocs_gen_files.open(full_doc_path, "w") as fd: + fd.write(f"::: {qualified_name}\n") - mkdocs_gen_files.set_edit_path(full_doc_path, path) # + mkdocs_gen_files.set_edit_path(full_doc_path, path) + +with mkdocs_gen_files.open(DOC_DIR / "nav.yml", "w") as nav_fd: + yaml.dump(nav_items, nav_fd, default_flow_style=False, sort_keys=False) diff --git a/pcdigitizer/data/dissociation_constant.py b/pcdigitizer/data/dissociation_constant.py index 379c182..0503fbc 100644 --- a/pcdigitizer/data/dissociation_constant.py +++ b/pcdigitizer/data/dissociation_constant.py @@ -73,16 +73,16 @@ class FlatPKaRecord(TypedDict): """ pka_label: str | None - """See [`ParsedPKa`][data.dissociation_constant.ParsedPKa.pka_label].""" + """See [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa.pka_label].""" pka_value: float - """See [`ParsedPKa`][data.dissociation_constant.ParsedPKa.pka_value].""" + """See [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa.pka_value].""" temperature_C: float | None - """See [`ParsedPKa`][data.dissociation_constant.ParsedPKa.temperature_C].""" + """See [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa.temperature_C].""" comment: str | None - """See [`ParsedPKa`][data.dissociation_constant.ParsedPKa.comment].""" + """See [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa.comment].""" _OUTPUT_SCHEMA: dict[str, type[pl.DataType]] = { @@ -101,27 +101,27 @@ class DissociationConstantData(AnnotationProcessor): """Parse and assemble PubChem dissociation constant annotation data. All methods are static or class methods. The primary public interface is - [`from_page`][data.dissociation_constant.DissociationConstantData.from_page], + [`from_page`][pcdigitizer.data.dissociation_constant.DissociationConstantData.from_page], which converts a raw list of PubChem annotation entries into a tidy polars DataFrame. The parsing pipeline for free-text pKa strings is the following. - 1. [`parse_value`][data.dissociation_constant.DissociationConstantData.parse_value] + 1. [`parse_value`][pcdigitizer.data.dissociation_constant.DissociationConstantData.parse_value] is the top-level dispatcher. It first checks for the "pKa values are X, Y, and Z" sentence form via - [`_parse_multi_value_sentence`][data.dissociation_constant.DissociationConstantData._parse_multi_value_sentence]. + [`_parse_multi_value_sentence`][pcdigitizer.data.dissociation_constant.DissociationConstantData._parse_multi_value_sentence]. If that does not match it splits the input on semicolons and delegates each segment to - [`_parse_part`][data.dissociation_constant.DissociationConstantData._parse_part]. + [`_parse_part`][pcdigitizer.data.dissociation_constant.DissociationConstantData._parse_part]. - 2. [`_parse_part`][data.dissociation_constant.DissociationConstantData._parse_part] + 2. [`_parse_part`][pcdigitizer.data.dissociation_constant.DissociationConstantData._parse_part] tries each compiled pattern in - [`_PATTERNS`][data.dissociation_constant.DissociationConstantData._PATTERNS] + [`_PATTERNS`][pcdigitizer.data.dissociation_constant.DissociationConstantData._PATTERNS] in priority order via - [`_try_patterns`][data.dissociation_constant.DissociationConstantData._try_patterns], + [`_try_patterns`][pcdigitizer.data.dissociation_constant.DissociationConstantData._try_patterns], returning the first successful - [`ParsedPKa`][data.dissociation_constant.ParsedPKa] or `None`. + [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa] or `None`. 3. Patterns are compiled once at class definition time and reused across all calls. @@ -197,7 +197,7 @@ class DissociationConstantData(AnnotationProcessor): Only used when a label group is present from one of the above patterns; this pattern has no label group intentionally, so bare numbers without any pK context are always rejected (see - [`_parse_part`][data.dissociation_constant.DissociationConstantData._parse_part] + [`_parse_part`][pcdigitizer.data.dissociation_constant.DissociationConstantData._parse_part] for the label guard). """ @@ -226,7 +226,7 @@ class DissociationConstantData(AnnotationProcessor): line: The raw input string to test. Returns: - A list of [`ParsedPKa`][data.dissociation_constant.ParsedPKa] records, + A list of [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa] records, one per numeric value found in the sentence, or `None` if this sentence form is not present in `line`. """ @@ -262,7 +262,7 @@ class DissociationConstantData(AnnotationProcessor): semicolons). Returns: - A [`ParsedPKa`][data.dissociation_constant.ParsedPKa] record if a pattern + A [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa] record if a pattern matches and a label is present, or `None` if no pattern yields a valid match. """ @@ -302,20 +302,20 @@ class DissociationConstantData(AnnotationProcessor): """Parse a single semicolon-split segment of a pKa string. Delegates to - [`_try_patterns`][data.dissociation_constant.DissociationConstantData._try_patterns] + [`_try_patterns`][pcdigitizer.data.dissociation_constant.DissociationConstantData._try_patterns] and logs a warning when no pattern matches, so that - [`parse_value`][data.dissociation_constant.DissociationConstantData.parse_value] + [`parse_value`][pcdigitizer.data.dissociation_constant.DissociationConstantData.parse_value] stays free of logging concerns. Args: part: A single segment, already stripped of leading/trailing whitespace and surrounding quotes. original_line: The full original input line, passed through to - [`_try_patterns`][data.dissociation_constant.DissociationConstantData._try_patterns] + [`_try_patterns`][pcdigitizer.data.dissociation_constant.DissociationConstantData._try_patterns] for provenance. Returns: - A [`ParsedPKa`][data.dissociation_constant.ParsedPKa] record, or + A [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa] record, or `None` if the segment could not be matched to any known pKa format. """ result = cls._try_patterns(part, original_line) @@ -389,7 +389,7 @@ class DissociationConstantData(AnnotationProcessor): The input may contain one or more pKa values separated by semicolons, or a prose sentence listing multiple values. Each recognized value is returned as a - [`ParsedPKa`][data.dissociation_constant.ParsedPKa] + [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa] record. Segments that cannot be matched to any known format are logged at WARNING level and excluded from the output. @@ -404,7 +404,7 @@ class DissociationConstantData(AnnotationProcessor): - `"pKa = 20"` Returns: - A list of [`ParsedPKa`][data.dissociation_constant.ParsedPKa] records, + A list of [`ParsedPKa`][pcdigitizer.data.dissociation_constant.ParsedPKa] records, one per recognized pKa value. Returns an empty list if no values could be parsed. """ @@ -438,9 +438,9 @@ class DissociationConstantData(AnnotationProcessor): Args: annotation_data: A list of annotation entry dicts as returned by - [`get_data`][pubchem.PubChemAPI.get_data] for + [`get_data`][pcdigitizer.pubchem.PubChemAPI.get_data] for the `"Dissociation Constants"` heading. Each entry is - expected to conform to [`AnnotationEntry`][responses.AnnotationEntry]. + expected to conform to [`AnnotationEntry`][pcdigitizer.responses.AnnotationEntry]. Returns: A polars DataFrame with one row per parsed pKa value diff --git a/pcdigitizer/pubchem.py b/pcdigitizer/pubchem.py index 795e1b0..a9196b9 100644 --- a/pcdigitizer/pubchem.py +++ b/pcdigitizer/pubchem.py @@ -20,7 +20,7 @@ class PubChemAPI: All methods are class methods or static methods; no instance state is required. Network access is centralized in - [`make_request`][pubchem.PubChemAPI.make_request] so that it can + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request] so that it can be replaced with a mock session during testing. """ @@ -82,7 +82,7 @@ class PubChemAPI: Args: url: The fully constructed PubChem REST URL to fetch. session: An optional [`Session`][requests.Session] forwarded to - [`make_request`][pubchem.PubChemAPI.make_request]. + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request]. See that method for details. Returns: @@ -90,7 +90,7 @@ class PubChemAPI: Raises: RuntimeError: If the HTTP request fails (propagated from - [`make_request`][pubchem.PubChemAPI.make_request]). + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request]). json.JSONDecodeError: If the response body is not valid JSON. """ text = cls.make_request(url, session=session) @@ -139,7 +139,7 @@ class PubChemAPI: Raises: ValueError: If `domain` is not in - [`ALLOWED_NAMESPACES`][pubchem.PubChemAPI.ALLOWED_NAMESPACES]. + [`ALLOWED_NAMESPACES`][pcdigitizer.pubchem.PubChemAPI.ALLOWED_NAMESPACES]. ValueError: If the namespace key is not valid for the given domain. ValueError: If `identifiers` is empty for a domain that requires it. ValueError: If `identifiers` contains characters outside the @@ -244,7 +244,7 @@ class PubChemAPI: Args: domain: The PubChem domain to query (e.g. `"compound"`, `"annotations"`). Must be a key in - [`ALLOWED_NAMESPACES`][pubchem.PubChemAPI.ALLOWED_NAMESPACES]. + [`ALLOWED_NAMESPACES`][pcdigitizer.pubchem.PubChemAPI.ALLOWED_NAMESPACES]. namespace: The namespace within the domain, optionally with a `/`-separated value (e.g. `"name"`, `"sourcename/ChEBI"`). pug: The PUG endpoint variant to use. Must be one of `"pug"`, @@ -262,15 +262,15 @@ class PubChemAPI: Returns: A fully constructed, validated HTTPS URL string ready to pass to - [`make_request`][pubchem.PubChemAPI.make_request]. + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request]. Raises: ValueError: If `pug` is not a recognized endpoint variant. ValueError: If `domain`, `namespace`, or `identifiers` fail validation (propagated from - [`_validate_components`][pubchem.PubChemAPI._validate_components]). + [`_validate_components`][pcdigitizer.pubchem.PubChemAPI._validate_components]). ValueError: If the resulting URL fails the safety check - (propagated from [`_validate_url`][pubchem.PubChemAPI._validate_url]). + (propagated from [`_validate_url`][pcdigitizer.pubchem.PubChemAPI._validate_url]). """ if pug not in cls._VALID_PUG_ENDPOINTS: raise ValueError( @@ -313,7 +313,7 @@ class PubChemAPI: Args: session: An optional [`Session`][requests.Session] forwarded to - [`make_request`][pubchem.PubChemAPI.make_request]. Pass a mock during + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request]. Pass a mock during testing to avoid live network calls. Returns: @@ -357,21 +357,21 @@ class PubChemAPI: Retrieves annotations from the `annotations/sourcename/` endpoint and groups them by type via - [`_process_annotations`][pubchem.PubChemAPI._process_annotations]. + [`_process_annotations`][pcdigitizer.pubchem.PubChemAPI._process_annotations]. Note: `output_format` is not exposed as a parameter here because - [`make_json`][pubchem.PubChemAPI.make_json] always expects a JSON response. + [`make_json`][pcdigitizer.pubchem.PubChemAPI.make_json] always expects a JSON response. To retrieve raw non-JSON data from this endpoint, use - [`build_url`][pubchem.PubChemAPI.build_url] and - [`make_request`][pubchem.PubChemAPI.make_request] directly. + [`build_url`][pcdigitizer.pubchem.PubChemAPI.build_url] and + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request] directly. Args: source_name: The PubChem depositor source name to query (e.g. `"ChEBI"`). Forward slashes are replaced with periods as required by the PubChem API. session: An optional [`Session`][requests.Session] forwarded to - [`make_request`][pubchem.PubChemAPI.make_request]. Pass a mock during + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request]. Pass a mock during testing to avoid live network calls. Returns: @@ -412,7 +412,7 @@ class PubChemAPI: Args: session: An optional [`Session`][requests.Session] forwarded to - [`make_request`][pubchem.PubChemAPI.make_request]. Pass a mock during + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request]. Pass a mock during testing to avoid live network calls. Returns: @@ -457,11 +457,11 @@ class PubChemAPI: Must be a positive integer. If `None`, all results are returned. session: An optional [`Session`][requests.Session]Session` forwarded to - [`make_request`][pubchem.PubChemAPI.make_request]. Pass a mock during + [`make_request`][pcdigitizer.pubchem.PubChemAPI.make_request]. Pass a mock during testing to avoid live network calls. Returns: - A list of [`AnnotationEntry`][responses.AnnotationEntry] dicts for the + A list of [`AnnotationEntry`][pcdigitizer.responses.AnnotationEntry] dicts for the requested data, in the order returned by the API. Raises: diff --git a/pcdigitizer/responses.py b/pcdigitizer/responses.py index 44705ff..72a6897 100644 --- a/pcdigitizer/responses.py +++ b/pcdigitizer/responses.py @@ -31,9 +31,9 @@ PubChem responses follow two broad envelope shapes depending on the endpoint: ``` Within both envelopes each `Annotation` element is an -[`AnnotationEntry`][responses.AnnotationEntry]. When the entry was fetched via +[`AnnotationEntry`][pcdigitizer.responses.AnnotationEntry]. When the entry was fetched via PUG-View (i.e. a specific heading), it additionally carries a `Data` list whose -elements are [`PubChemDatum`][responses.PubChemDatum] records containing the +elements are [`PubChemDatum`][pcdigitizer.responses.PubChemDatum] records containing the deposited values. ## Hierarchy @@ -61,7 +61,7 @@ from typing import TypedDict class MatchedRecord(TypedDict, total=False): """The `Matched` sub-object within an - [`ExtendedReference`][responses.ExtendedReference] entry. + [`ExtendedReference`][pcdigitizer.responses.ExtendedReference] entry. Carries identifiers that link a specific deposited value to its corresponding record in PubChem's live data system. @@ -103,7 +103,7 @@ class DatumValue(TypedDict, total=False): """The `Value` object on a single data point within an annotation. PubChem data points can carry several value types (numeric, boolean, binary). - This class models only the [`StringWithMarkup`][responses.StringWithMarkup] + This class models only the [`StringWithMarkup`][pcdigitizer.responses.StringWithMarkup] variant, which is the form used for textual property data such as pKa strings. """ @@ -117,14 +117,14 @@ class DatumValue(TypedDict, total=False): class PubChemDatum(TypedDict, total=False): """A single data point within a PubChem PUG-View annotation entry. - Each [`AnnotationEntry`][responses.AnnotationEntry] fetched from a specific heading + Each [`AnnotationEntry`][pcdigitizer.responses.AnnotationEntry] fetched from a specific heading contains a `Data` list whose elements are `PubChemDatum` records. Each datum represents one deposited measurement or value from a single source. """ Value: DatumValue """ - The deposited value, in [`StringWithMarkup`][responses.StringWithMarkup] + The deposited value, in [`StringWithMarkup`][pcdigitizer.responses.StringWithMarkup] form for textual properties. """