Skip to content

Commit 951b3ff

Browse files
committed
DOP-2649: Permit specifying an rstspec.toml file
1 parent 44063c5 commit 951b3ff

File tree

6 files changed

+36
-8
lines changed

6 files changed

+36
-8
lines changed

snooty/main.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Snooty.
22
33
Usage:
4-
snooty build [--no-caching] <source-path> [<mongodb-url>] [--commit=<commit_hash> | (--commit=<commit_hash> --patch=<patch_id>)]
4+
snooty build [--no-caching] <source-path> [<mongodb-url>] [options]
55
snooty watch [--no-caching] <source-path>
66
snooty [--no-caching] language-server
77
@@ -10,6 +10,7 @@
1010
--commit=<commit_hash> Commit hash of build.
1111
--patch=<patch_id> Patch ID of build. Must be specified with a commit hash.
1212
--no-caching Disable HTTP response caching.
13+
--rstspec=<url> Override the reStructuredText directive & role spec.
1314
1415
Environment variables:
1516
SNOOTY_PARANOID 0, 1 where 0 is default
@@ -34,7 +35,7 @@
3435
import watchdog.observers
3536
from docopt import docopt
3637

37-
from . import __version__, language_server
38+
from . import __version__, language_server, specparser
3839
from .diagnostics import Diagnostic, MakeCorrectionMixin
3940
from .page import Page
4041
from .parser import Project, ProjectBackend
@@ -280,6 +281,15 @@ def main() -> None:
280281

281282
logger.info(f"Snooty {__version__} starting")
282283

284+
if args["--rstspec"]:
285+
rstspec_path = args["--rstspec"]
286+
if rstspec_path.startswith("https://") or rstspec_path.startswith("http://"):
287+
rstspec_bytes = HTTPCache.singleton().get(args["--rstspec"])
288+
rstspec_text = str(rstspec_bytes, "utf-8")
289+
else:
290+
rstspec_text = Path(rstspec_path).read_text(encoding="utf-8")
291+
specparser.Spec.initialize(rstspec_text)
292+
283293
if PARANOID_MODE:
284294
logger.info("Paranoid mode on")
285295

snooty/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ def handle_tabset(self, node: n.Directive) -> None:
492492
line = node.start[0]
493493
# retrieve dictionary associated with this specific tabset
494494
try:
495-
tab_definitions_list = specparser.SPEC.tabs[tabset]
495+
tab_definitions_list = specparser.Spec.get().tabs[tabset]
496496
except KeyError:
497497
self.diagnostics.append(UnknownTabset(tabset, line))
498498
return

snooty/postprocess.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,7 @@ def __init__(self, context: Context) -> None:
12421242
super().__init__(context)
12431243
self.project_config = context[ProjectConfig]
12441244
self.targets = context[TargetDatabase]
1245+
self.spec = specparser.Spec.get()
12451246

12461247
def enter_node(self, fileid_stack: FileIdStack, node: n.Node) -> None:
12471248
"""When a node of type ref_role is encountered, ensure that it references a valid target.
@@ -1265,7 +1266,7 @@ def enter_node(self, fileid_stack: FileIdStack, node: n.Node) -> None:
12651266
if not target_candidates:
12661267
# insert title and raise diagnostic
12671268
line = node.span[0]
1268-
target_dict = specparser.SPEC.rstobject
1269+
target_dict = self.spec.rstobject
12691270
target_key = f"{node.domain}:{node.name}"
12701271
title = node.target
12711272
# abstract title from node's target to insert into new text node

snooty/rstparser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ def get(cls, default_domain: Optional[str]) -> "Registry":
10221022
):
10231023
return cls.CURRENT_REGISTRY[1]
10241024

1025-
registry = register_spec_with_docutils(specparser.SPEC, default_domain)
1025+
registry = register_spec_with_docutils(specparser.Spec.get(), default_domain)
10261026
cls.CURRENT_REGISTRY = (default_domain, registry)
10271027
return registry
10281028

snooty/specparser.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
"""Parser for a TOML spec file containing definitions of all supported reStructuredText
22
directives and roles, and what types of data each should expect."""
33

4+
from __future__ import annotations
5+
46
import dataclasses
57
from dataclasses import dataclass, field
68
from enum import Enum
79
from typing import (
810
Any,
911
Callable,
12+
ClassVar,
1013
Dict,
1114
FrozenSet,
1215
List,
@@ -271,6 +274,8 @@ class Spec:
271274
rstobject: Dict[str, RstObject] = field(default_factory=dict)
272275
tabs: Dict[str, List[TabDefinition]] = field(default_factory=dict)
273276

277+
SPEC: ClassVar[Optional[Spec]] = None
278+
274279
@classmethod
275280
def loads(cls, data: str) -> "Spec":
276281
"""Load a spec from a string."""
@@ -392,6 +397,16 @@ def resolve_value(key: str, inheritable: _T) -> _T:
392397
for key, inheritable in inheritable_index.items():
393398
resolve_value(key, inheritable)
394399

400+
@classmethod
401+
def initialize(cls, text: str) -> None:
402+
cls.SPEC = Spec.loads(text)
395403

396-
GLOBAL_SPEC_PATH = util.PACKAGE_ROOT.joinpath("rstspec.toml")
397-
SPEC = Spec.loads(GLOBAL_SPEC_PATH.read_text(encoding="utf-8"))
404+
@classmethod
405+
def get(cls) -> "Spec":
406+
if cls.SPEC is None:
407+
path = util.PACKAGE_ROOT.joinpath("rstspec.toml")
408+
cls.initialize(path.read_text(encoding="utf-8"))
409+
410+
spec = cls.SPEC
411+
assert spec is not None
412+
return spec

snooty/target_database.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ def __getitem__(self, key: str) -> Sequence["TargetDatabase.Result"]:
5656
key = normalize_target(key)
5757
results: List[TargetDatabase.Result] = []
5858

59+
spec = specparser.Spec.get()
60+
5961
with self.lock:
6062
# Check to see if the target is defined locally
6163
try:
@@ -93,7 +95,7 @@ def __getitem__(self, key: str) -> Sequence["TargetDatabase.Result"]:
9395
if display_name is None:
9496
display_name = entry.name
9597

96-
display_name = specparser.SPEC.strip_prefix_from_name(
98+
display_name = spec.strip_prefix_from_name(
9799
entry.domain_and_role, display_name
98100
)
99101

0 commit comments

Comments
 (0)