Skip to content

docs(context): fix unrunnable ContextGraph docstring example - #921

Open
pravit-amp wants to merge 3 commits into
semantica-agi:mainfrom
pravit-amp:fix/920-context-graph-docstring-example
Open

docs(context): fix unrunnable ContextGraph docstring example#921
pravit-amp wants to merge 3 commits into
semantica-agi:mainfrom
pravit-amp:fix/920-context-graph-docstring-example

Conversation

@pravit-amp

Copy link
Copy Markdown
Contributor

Description

The Example Usage block in the ContextGraph module docstring could not be run as written. Three lines passed keyword arguments the target methods do not accept.

add_node(node_id, node_type, content=None, **properties) takes node_type positionally and has no properties parameter, so the documented call raised TypeError. add_edge's parameter is edge_type, so type= fell through to **properties and polluted edge metadata while appearing to work.

Two of the three broken forms failed silently rather than raising — storing a nested properties dict or a stray type key instead of erroring — which is why this was worth a regression guard rather than just a text fix.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Code refactoring

Related Issues

Closes #920

Changes Made

  • semantica/context/context_graph.py:75-77 — pass node_type/edge_type positionally and node properties as **kwargs
  • tests/context/test_context_graph_docstring_example.py — new regression tests (6): execute the documented calls, assert node properties are stored flat rather than nested, assert the edge type is not a stray metadata key, and fail if the docstring reintroduces type=/properties= on those lines
  • No runtime behaviour changes — the API is unchanged; only the documented call form was wrong

Testing

  • Tested locally
  • Added tests for new functionality
  • Package builds successfully (python -m build)

Verified the regression guard actually fails: restored the original docstring, confirmed 2 of the 6 tests fail with their diagnostic messages, then restored the fix and confirmed all 6 pass.

Scope check: every add_node(/add_edge( call site in the repo already uses the correct form. The remaining type= hits are NetworkX graphs (semantica/split/methods.py:1190, tests/kg/test_link_predictor.py), a different API.

Test Commands

# New regression tests
pytest tests/context/test_context_graph_docstring_example.py -q   # 6 passed

# Full context suite — unchanged from main
pytest tests/context/ -q                                          # 486 passed

# Build
python -m build                                                   # semantica-0.6.5.tar.gz + wheel

# Lint (new file)
black --check tests/context/test_context_graph_docstring_example.py
isort --profile black --line-length 88 --check-only tests/context/test_context_graph_docstring_example.py
flake8 --max-line-length=88 --extend-ignore=E203,W503 tests/context/test_context_graph_docstring_example.py

Documentation

  • Updated relevant documentation
  • Added code examples if applicable
  • Updated API reference if adding new APIs
  • Updated cookbook if adding new examples
  • No documentation changes needed

Breaking Changes

Breaking Changes: No

The change is confined to a docstring plus a new test file. No signatures, behaviour, or public API affected.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • Package builds successfully

Additional Notes

Two deliberate scope decisions, flagged for reviewers:

  1. black/isort want to reformat pre-existing regions of context_graph.py (import ordering, the ..kg import block, trailing whitespace on the untouched >>> lines at 73/81). I did not apply any of it — it is unrelated to this fix and would bury a 3-line diff in noise. Happy to open a separate formatting PR if that is wanted.

  2. find_precedents("loan_approval", limit=5) at line 91 may be a fourth defective line. The signature is find_precedents(decision_id, limit=10), but the example passes a category. It returns [] rather than raising, so the example runs — it just demonstrates incorrect usage. There is a separate find_precedents_by_scenario that may be what was intended. I left it out because the correct fix depends on maintainer intent and would pull a design question into a docs PR. Happy to include it here or file it separately, whichever you prefer.

The module docstring's Example Usage block called add_node/add_edge with
keyword arguments they do not accept. add_node(node_id, node_type, ...) takes
node_type positionally and has no properties parameter, so the documented call
raised TypeError; add_edge's parameter is edge_type, so type= fell through to
**properties and polluted edge metadata while appearing to work.

Two of the three broken forms failed silently rather than raising, storing a
nested properties dict or a stray type key instead of erroring.

Add regression tests that execute the documented calls and assert the docstring
itself does not reintroduce the invalid kwargs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix ContextGraph docstring example and add regression tests

📝 Documentation 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Fix ContextGraph docstring example to match add_node/add_edge positional parameters.
• Add regression tests to ensure the documented calls remain runnable.
• Prevent silent metadata pollution from mistaken type=/properties= kwargs in docs.
Diagram

graph TD
  T[["tests/context/test_context_graph_docstring_example.py"]] --> R["Docstring parser"] --> D["context_graph.py docstring"] --> C(["ContextGraph add_node/add_edge"]) --> S[("In-memory nodes/edges")]

  subgraph Legend
    direction LR
    _test[["Test file"]] ~~~ _mod["Helper module"] ~~~ _file["Source/doc file"] ~~~ _api(["API surface"]) ~~~ _store[("Data store")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use Python doctest for the module docstring
  • ➕ Validates the docstring exactly as rendered, without custom regex parsing
  • ➕ Standard tooling; can run as part of pytest collection
  • ➖ Doctests can be brittle (whitespace/output sensitivity) and may execute more of the example than desired
  • ➖ Harder to add targeted assertions about silent metadata pollution beyond “it runs”
2. Move example into a runnable snippet and reference it from the docstring
  • ➕ Single source of truth: the same snippet can be imported/executed in tests and embedded in docs
  • ➕ Avoids regex parsing of docstrings
  • ➖ Adds indirection/boilerplate to keep the docstring readable
  • ➖ Requires a convention/tooling for embedding external snippets into docstrings

Recommendation: Keep the current approach: a small docstring fix plus explicit pytest regression coverage. It’s less brittle than doctest while still ensuring the docstring text doesn’t regress (string-level guard) and that the example’s semantics are correct (properties stay flat; edge_type isn’t a stray metadata key).

Files changed (2) +113 / -3

Tests (1) +110 / -0
test_context_graph_docstring_example.pyAdd regression tests to keep ContextGraph docstring example runnable +110/-0

Add regression tests to keep ContextGraph docstring example runnable

• Introduces tests that (1) execute the documented add_node/add_edge calls, (2) assert node properties are stored flat and edge_type is not treated as metadata, and (3) parse the docstring text to fail if 'type='/'properties=' reappear in the example. Also pins the expected TypeError for the previously broken call form.

tests/context/test_context_graph_docstring_example.py

Documentation (1) +3 / -3
context_graph.pyFix Example Usage calls to match add_node/add_edge signatures +3/-3

Fix Example Usage calls to match add_node/add_edge signatures

• Updates the module docstring’s Basic graph operations example to pass node_type/edge_type positionally and node properties via **kwargs. This makes the example runnable and avoids silently nesting properties or polluting edge metadata via an unintended 'type' key.

semantica/context/context_graph.py

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 11, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Docstring guard false-negative ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new docstring-regression tests can pass without checking any graph.add_node/graph.add_edge
lines because _example_block() captures only up to the first blank line after Example Usage: and
the re.findall(...) loops don’t assert that they matched anything. A docstring formatting change
(e.g., inserting a blank line after the header or wrapping calls across lines) can therefore
reintroduce type=/properties= into the docstring while CI stays green.
Code

tests/context/test_context_graph_docstring_example.py[R84-87]

+        block = _example_block()
+        for line in re.findall(r">>> graph\.add_node\(.*", block):
+            assert "type=" not in line, (
+                f"add_node example passes type= as a keyword: {line!r}. "
Evidence
_example_block() uses a fragile \n\n terminator and the guard tests don’t assert that any
add_node/add_edge lines were matched, so the loops can be skipped entirely and still pass. The
current module docstring has a blank line before the next section header, and adding an additional
blank line earlier (or multiline calls) would truncate/empty the captured block and defeat the guard
checks.

tests/context/test_context_graph_docstring_example.py[22-27]
tests/context/test_context_graph_docstring_example.py[83-105]
semantica/context/context_graph.py[67-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The regression tests intended to guard the `ContextGraph` module docstring can miss regressions:
- `_example_block()` stops at the first `\n\n`, so a harmless formatting change can truncate/empty the captured example.
- The guard tests iterate over `re.findall(...)` results but do not assert any matches, so they can pass while checking nothing.
## Issue Context
The goal of these tests is to fail if the module docstring reintroduces `type=` / `properties=` usage in the `add_node`/`add_edge` example.
## Fix Focus Areas
- tests/context/test_context_graph_docstring_example.py[22-27]
- tests/context/test_context_graph_docstring_example.py[83-105]
## Suggested fix
1. Make `_example_block()` extraction robust to additional blank lines by terminating on the next section header instead of `\n\n` (e.g., match until `^Production Use Cases:` with `re.MULTILINE`, or match until end-of-docstring).
2. In each guard test, first collect matches into a list and assert it’s non-empty, e.g.:
- `node_lines = re.findall(...)` then `assert node_lines, "Expected add_node examples in docstring"`
- same for `add_edge`
3. (Optional but strongest) Consider executing the extracted `>>>` lines via `doctest` or a small parser so the “runnable” test can’t drift from the docstring.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread tests/context/test_context_graph_docstring_example.py Outdated
Pravit Ampapathini and others added 2 commits August 11, 2026 15:05
The guards added in the previous commit could pass while checking nothing.

_example_block() terminated the capture at the first "\n\n". The Example
Usage block already contains ">>> " spacer lines, so any reformatting that
turned one into a bare blank line would truncate the capture -- potentially
to empty -- and the guards would then scan a block that no longer held the
add_node/add_edge calls they exist to police.

Both guards also iterated over re.findall() without asserting a match. Zero
matches meant zero assertions and a green test, so the two failure modes
compounded: a truncated block produced no matches, and no matches produced
a pass.

Terminate the block at the next top-level section header (^\S) or end of
docstring instead, so blank lines inside the example are harmless, and
assert the captured block, the parsed statement list, and each guard's
match list are all non-empty.

Extract statements with doctest.DocTestParser rather than a line regex.
This also catches a call reformatted across "..." continuation lines, which
the ">>> graph.add_node(.*" pattern silently skipped, and lets
test_documented_calls_execute exec the docstring's own statements instead
of a retyped copy that could drift from it. Full doctest.testmod isn't
usable here: add_node/add_edge return True and the docs carry no
expected-output lines, so it reports 4 spurious failures.

Narrow the kwarg check to (?<![\w])type\s*= so a legitimate node_type=
or edge_type= in the docs no longer trips a guard aimed at bare type=.

Verified by mutating the module docstring and re-running the guards: extra
blank lines with a valid example still pass; regressed add_node/add_edge,
a type= on a continuation line, deleted calls, and a deleted section all
fail; a legitimate node_type= passes. 6 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(context): ContextGraph module docstring example is not runnable — add_node()/add_edge() signature mismatch

1 participant