sphinx-codelinks 2.0.0__tar.gz → 2.1.0__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.
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/PKG-INFO +5 -4
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/pyproject.toml +9 -7
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/__init__.py +1 -1
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/analyse.py +39 -24
- sphinx_codelinks-2.1.0/src/sphinx_codelinks/analyse/entity.py +1610 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/models.py +23 -9
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/utils.py +265 -192
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/config.py +12 -7
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/needextend_write.py +11 -3
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/source_discover/config.py +4 -1
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/debug.py +45 -7
- sphinx_codelinks-2.1.0/src/sphinx_codelinks/sphinx_extension/directives/__init__.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/directives/src_trace.py +230 -73
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/html_wrapper.py +10 -2
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/need_id_refs.py +13 -3
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/source_tracing.py +6 -4
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/LICENSE +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/README.md +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/__init__.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/multiline_parser.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/oneline_parser.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/preproc/__init__.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/preproc/compile_db.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/preproc/libclang_parser.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/preproc/loader.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/projects.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/analyse/references.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/cmd.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/logger.py +0 -0
- /sphinx_codelinks-2.0.0/src/sphinx_codelinks/source_discover/__init__.py → /sphinx_codelinks-2.1.0/src/sphinx_codelinks/py.typed +0 -0
- {sphinx_codelinks-2.0.0/src/sphinx_codelinks/sphinx_extension → sphinx_codelinks-2.1.0/src/sphinx_codelinks/source_discover}/__init__.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/source_discover/source_discover.py +0 -0
- {sphinx_codelinks-2.0.0/src/sphinx_codelinks/sphinx_extension/directives → sphinx_codelinks-2.1.0/src/sphinx_codelinks/sphinx_extension}/__init__.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/project_analysis.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/rediscovery.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/string_links.py +0 -0
- {sphinx_codelinks-2.0.0 → sphinx_codelinks-2.1.0}/src/sphinx_codelinks/sphinx_extension/ub_sct.css +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sphinx-codelinks
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Fast Source Code Traceability for Sphinx-Needs
|
|
5
5
|
Author-email: team useblocks <info@useblocks.com>
|
|
6
6
|
Maintainer-email: Marco Heinemann <marco.heinemann@useblocks.com>, Jui-Wen Chen <jui-wen.chen@useblocks.com>
|
|
7
7
|
Requires-Python: >=3.11,<4
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
|
+
Classifier: Typing :: Typed
|
|
9
10
|
License-File: LICENSE
|
|
10
11
|
Requires-Dist: comment-parser>=1.2.4
|
|
11
12
|
Requires-Dist: ignore-python>=0.3.3
|
|
12
13
|
Requires-Dist: typer>=0.16.0
|
|
13
14
|
Requires-Dist: jsonschema
|
|
14
15
|
Requires-Dist: sphinx>=7.4,<10
|
|
15
|
-
Requires-Dist: sphinx-needs>=9.
|
|
16
|
-
Requires-Dist: ub-project>=1.
|
|
16
|
+
Requires-Dist: sphinx-needs>=9.2.0,<10
|
|
17
|
+
Requires-Dist: ub-project>=1.2.0,<2
|
|
17
18
|
Requires-Dist: jinja2
|
|
18
19
|
Requires-Dist: pygments
|
|
19
20
|
Requires-Dist: docutils>=0.21
|
|
@@ -28,7 +29,7 @@ Requires-Dist: tree-sitter-rust>=0.23.0
|
|
|
28
29
|
Requires-Dist: tree-sitter-go>=0.23.0
|
|
29
30
|
Requires-Dist: tree-sitter-json>=0.24.8
|
|
30
31
|
Requires-Dist: tree-sitter-bash>=0.25.1
|
|
31
|
-
Requires-Dist: furo>=
|
|
32
|
+
Requires-Dist: furo>=2025.12.19 ; extra == "docs"
|
|
32
33
|
Requires-Dist: myst-parser>=4.0.0 ; extra == "docs"
|
|
33
34
|
Requires-Dist: sphinx-ai-index>=1.0.0,<2 ; extra == "docs"
|
|
34
35
|
Requires-Dist: sphinx-design>=0.6.1 ; extra == "docs"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sphinx-codelinks"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.1.0"
|
|
4
4
|
description = "Fast Source Code Traceability for Sphinx-Needs"
|
|
5
5
|
authors = [{ name = "team useblocks", email = "info@useblocks.com" }]
|
|
6
6
|
maintainers = [
|
|
@@ -15,6 +15,7 @@ readme = "README.md"
|
|
|
15
15
|
# locks, builds and publishes -- the gap shows up only as an install failure for a user on
|
|
16
16
|
# an interpreter inside it.
|
|
17
17
|
requires-python = ">=3.11,<4"
|
|
18
|
+
classifiers = ["Typing :: Typed"]
|
|
18
19
|
dependencies = [
|
|
19
20
|
"comment-parser>=1.2.4",
|
|
20
21
|
"ignore-python>=0.3.3",
|
|
@@ -27,8 +28,8 @@ dependencies = [
|
|
|
27
28
|
# edge. uv never validates a specifier it resolves through `workspace = true` (uv#9811),
|
|
28
29
|
# so the floor is the only statement of what was actually tested, and the cap is what
|
|
29
30
|
# stops a future major being co-installed with a wheel written against this one.
|
|
30
|
-
"sphinx-needs>=9.
|
|
31
|
-
"ub-project>=1.
|
|
31
|
+
"sphinx-needs>=9.2.0,<10",
|
|
32
|
+
"ub-project>=1.2.0,<2",
|
|
32
33
|
"jinja2",
|
|
33
34
|
"pygments",
|
|
34
35
|
"docutils>=0.21", # the `typing` group's series
|
|
@@ -64,7 +65,7 @@ libclang = ["libclang>=16"]
|
|
|
64
65
|
# the root there re-exports each member's extra (`docs-mounts = ["sphinx-mounts[docs]"]`),
|
|
65
66
|
# because `uv sync --extra` resolves against the workspace root rather than the member.
|
|
66
67
|
docs = [
|
|
67
|
-
"furo>=
|
|
68
|
+
"furo>=2025.12.19",
|
|
68
69
|
"myst-parser>=4.0.0",
|
|
69
70
|
"sphinx-ai-index>=1.0.0,<2",
|
|
70
71
|
"sphinx-design>=0.6.1",
|
|
@@ -84,9 +85,10 @@ Changelog = "https://github.com/useblocks/sphinx-needs/blob/master/packages/sphi
|
|
|
84
85
|
requires = ["flit_core >=3.4,<4"]
|
|
85
86
|
build-backend = "flit_core.buildapi"
|
|
86
87
|
|
|
87
|
-
# Deliberately NO `[tool.flit.sdist]`: this distribution carries
|
|
88
|
-
#
|
|
89
|
-
#
|
|
88
|
+
# Deliberately NO `[tool.flit.sdist]`: this distribution carries nothing outside the module
|
|
89
|
+
# (its `py.typed` marker included, which flit ships as part of it), so flit's module-only
|
|
90
|
+
# sdist is the shape already published on PyPI, and nothing downstream builds from it --
|
|
91
|
+
# the git pins in the wild clone the repository.
|
|
90
92
|
# Everything else -- ruff, ty, pytest and the dependency groups -- is the ROOT's, and
|
|
91
93
|
# `tools/src/sn_tools/check_workspace.py` check (7) refuses those tables here: a member
|
|
92
94
|
# `[tool.ruff]` does not extend the root's configuration, it replaces it.
|
|
@@ -9,6 +9,7 @@ from tree_sitter import Node as TreeSitterNode
|
|
|
9
9
|
from tree_sitter import Parser, Query
|
|
10
10
|
|
|
11
11
|
from sphinx_codelinks.analyse import multiline_parser, utils
|
|
12
|
+
from sphinx_codelinks.analyse.entity import CodeScope, code_scope, scope_language
|
|
12
13
|
from sphinx_codelinks.analyse.models import (
|
|
13
14
|
MarkedContentType,
|
|
14
15
|
MultilineNeed,
|
|
@@ -363,9 +364,14 @@ class SourceAnalyse:
|
|
|
363
364
|
# ``c`` is a LibclangComment duck-typing the tree-sitter Node
|
|
364
365
|
# interface SourceComment reads (``.text`` / ``.start_point.row``);
|
|
365
366
|
# the Node-only path (find_associated_scope) is guarded by
|
|
366
|
-
# ``is_libclang`` so it never runs on these.
|
|
367
|
+
# ``is_libclang`` so it never runs on these. The cast is that duck typing,
|
|
368
|
+
# which is why ty, seeing two unrelated classes, has to be told.
|
|
367
369
|
src_comments = [
|
|
368
|
-
SourceComment(
|
|
370
|
+
SourceComment(
|
|
371
|
+
cast("TreeSitterNode", c), # ty: ignore[disjoint-cast]
|
|
372
|
+
c.column,
|
|
373
|
+
)
|
|
374
|
+
for c in comments
|
|
369
375
|
]
|
|
370
376
|
src_file = SourceFile(src_path.absolute())
|
|
371
377
|
src_file.add_comments(src_comments)
|
|
@@ -415,11 +421,13 @@ class SourceAnalyse:
|
|
|
415
421
|
src_comment: SourceComment,
|
|
416
422
|
first_row: int | None = None,
|
|
417
423
|
first_column: int | None = None,
|
|
424
|
+
*,
|
|
425
|
+
scope: CodeScope | None = None,
|
|
418
426
|
) -> list[NeedIdRefs]:
|
|
419
427
|
"""Extract need-ids-refs from a comment.
|
|
420
428
|
|
|
421
429
|
``text`` starts at ``first_row`` and ``first_column`` (by default the
|
|
422
|
-
comment's own row and column).
|
|
430
|
+
comment's own row and column). ``scope`` is the named ``tagged_scope``.
|
|
423
431
|
"""
|
|
424
432
|
if first_row is None:
|
|
425
433
|
first_row = src_comment.node.start_point.row
|
|
@@ -463,6 +471,7 @@ class SourceAnalyse:
|
|
|
463
471
|
tagged_scope,
|
|
464
472
|
need_ids,
|
|
465
473
|
marker,
|
|
474
|
+
scope=scope,
|
|
466
475
|
)
|
|
467
476
|
)
|
|
468
477
|
return anchors
|
|
@@ -573,11 +582,13 @@ class SourceAnalyse:
|
|
|
573
582
|
oneline_comment_style: OneLineCommentStyle,
|
|
574
583
|
first_row: int | None = None,
|
|
575
584
|
first_column: int | None = None,
|
|
585
|
+
*,
|
|
586
|
+
scope: CodeScope | None = None,
|
|
576
587
|
) -> list[OneLineNeed]:
|
|
577
588
|
"""Extract the one-line needs of a comment.
|
|
578
589
|
|
|
579
590
|
``text`` starts at ``first_row`` and ``first_column`` (by default the
|
|
580
|
-
comment's own row and column).
|
|
591
|
+
comment's own row and column). ``scope`` is the named ``tagged_scope``.
|
|
581
592
|
"""
|
|
582
593
|
if first_row is None:
|
|
583
594
|
first_row = src_comment.node.start_point.row
|
|
@@ -621,6 +632,7 @@ class SourceAnalyse:
|
|
|
621
632
|
src_comment,
|
|
622
633
|
tagged_scope,
|
|
623
634
|
resolved, # int arguments were deleted # ty: ignore[invalid-argument-type]
|
|
635
|
+
scope=scope,
|
|
624
636
|
)
|
|
625
637
|
)
|
|
626
638
|
return oneline_needs
|
|
@@ -689,11 +701,7 @@ class SourceAnalyse:
|
|
|
689
701
|
),
|
|
690
702
|
run.comments[0],
|
|
691
703
|
)
|
|
692
|
-
tagged_scope
|
|
693
|
-
if not getattr(src_comment.node, "is_libclang", False):
|
|
694
|
-
tagged_scope = utils.find_associated_scope(
|
|
695
|
-
src_comment.node, self.analyse_config.comment_type
|
|
696
|
-
)
|
|
704
|
+
tagged_scope, scope = self._associate(src_comment, filepath)
|
|
697
705
|
lineno = block.open_row + 1
|
|
698
706
|
remote_url = self.git_remote_url
|
|
699
707
|
if self.git_remote_url and self.git_commit_rev:
|
|
@@ -713,15 +721,6 @@ class SourceAnalyse:
|
|
|
713
721
|
if block.content_start is not None
|
|
714
722
|
else None
|
|
715
723
|
)
|
|
716
|
-
scope = (
|
|
717
|
-
{
|
|
718
|
-
"kind": tagged_scope.type,
|
|
719
|
-
"start": tagged_scope.start_point.row + 1,
|
|
720
|
-
"end": tagged_scope.end_point.row + 1,
|
|
721
|
-
}
|
|
722
|
-
if tagged_scope is not None
|
|
723
|
-
else None
|
|
724
|
-
)
|
|
725
724
|
source: dict[str, Any] = {
|
|
726
725
|
"project": self.name,
|
|
727
726
|
"path": _relative_posix(filepath, self.project_path),
|
|
@@ -742,6 +741,25 @@ class SourceAnalyse:
|
|
|
742
741
|
block.need,
|
|
743
742
|
block.markup,
|
|
744
743
|
source,
|
|
744
|
+
scope=scope,
|
|
745
|
+
)
|
|
746
|
+
|
|
747
|
+
def _associate(
|
|
748
|
+
self, src_comment: SourceComment, filepath: Path
|
|
749
|
+
) -> tuple[TreeSitterNode | None, CodeScope | None]:
|
|
750
|
+
"""The entity a comment of ``filepath`` is attached to: its node and its
|
|
751
|
+
``scope`` object.
|
|
752
|
+
|
|
753
|
+
A libclang comment has no tree-sitter node, so it is attached to nothing.
|
|
754
|
+
"""
|
|
755
|
+
if getattr(src_comment.node, "is_libclang", False):
|
|
756
|
+
return None, None
|
|
757
|
+
comment_type = self.analyse_config.comment_type
|
|
758
|
+
association = utils.associate(src_comment.node, comment_type)
|
|
759
|
+
if association is None or not association.node.text:
|
|
760
|
+
return None, None
|
|
761
|
+
return association.node, code_scope(
|
|
762
|
+
association, comment_type, scope_language(comment_type, filepath)
|
|
745
763
|
)
|
|
746
764
|
|
|
747
765
|
def extract_marked_content(self) -> None:
|
|
@@ -756,12 +774,7 @@ class SourceAnalyse:
|
|
|
756
774
|
)
|
|
757
775
|
if not filepath:
|
|
758
776
|
continue
|
|
759
|
-
|
|
760
|
-
tagged_scope: TreeSitterNode | None = None
|
|
761
|
-
else:
|
|
762
|
-
tagged_scope = utils.find_associated_scope(
|
|
763
|
-
src_comment.node, self.analyse_config.comment_type
|
|
764
|
-
)
|
|
777
|
+
tagged_scope, scope = self._associate(src_comment, filepath)
|
|
765
778
|
for text, first_row, first_column in _scanned_texts(
|
|
766
779
|
src_comment, claimed.get(id(src_comment))
|
|
767
780
|
):
|
|
@@ -774,6 +787,7 @@ class SourceAnalyse:
|
|
|
774
787
|
src_comment,
|
|
775
788
|
first_row,
|
|
776
789
|
first_column,
|
|
790
|
+
scope=scope,
|
|
777
791
|
)
|
|
778
792
|
)
|
|
779
793
|
if self.analyse_config.get_oneline_needs:
|
|
@@ -786,6 +800,7 @@ class SourceAnalyse:
|
|
|
786
800
|
self.analyse_config.oneline_comment_style,
|
|
787
801
|
first_row,
|
|
788
802
|
first_column,
|
|
803
|
+
scope=scope,
|
|
789
804
|
)
|
|
790
805
|
)
|
|
791
806
|
|