Skip to content

Fix vscode integration #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 82 commits into from
Mar 9, 2025
Merged

Fix vscode integration #54

merged 82 commits into from
Mar 9, 2025

Conversation

MusicalNinjaDad
Copy link
Owner

@MusicalNinjaDad MusicalNinjaDad commented Mar 9, 2025

Summary by Sourcery

Fixes integration with VS Code's test explorer by changing the CellPath format to use subscript notation (path/to/notebook.ipynb[Celln]) and patching pytest to handle this new format.

Bug Fixes:

  • Fix integration with vscode Test Explorer

Enhancements:

  • CellPath now uses subscript format path/to/notebook.ipynb[Celln]

This mainly restores to:
83bd338
… doesn't fix the exception repr"

This reverts commit 1503044.
Copy link
Contributor

sourcery-ai bot commented Mar 9, 2025

Reviewer's Guide by Sourcery

This pull request fixes the vscode integration by changing the CellPath format to path/to/notebook.ipynb[Celln], implementing command line argument handling for CellPaths, monkeypatching pytest to handle CellPath, and reverting patches after the session. It also removes unnecessary conftest entries in tests.

Sequence diagram for pytest Cell collection

sequenceDiagram
  participant pytest
  participant Notebook
  participant Cell
  participant ParsedNotebook

  pytest->>Notebook: pytest_collect_file(file_path, parent)
  Notebook->>ParsedNotebook: _ParsedNotebook(self.path)
  loop for each testcellid in parsed.muggled_testcells.ids()
    Notebook->>Cell: Cell.from_parent(parent, name, nodeid, path)
    Cell-->>Notebook: cell
    Notebook->>Cell: cell.stash[ipynb2_notebook] = parsed
    Notebook->>Cell: cell.stash[ipynb2_cellid] = testcellid
    Notebook-->>pytest: yield cell
  end
Loading

Sequence diagram for pytest session start and finish

sequenceDiagram
  participant pytest
  participant CellPath

  pytest->>CellPath: pytest_sessionstart(session)
  CellPath->>CellPath: patch_pytest_absolutepath()
  CellPath-->>pytest: Monkeypatches

  pytest->>CellPath: pytest_sessionfinish(session, exitstatus)
  CellPath->>CellPath: Revert Monkeypatches
  CellPath-->>pytest: None
Loading

Updated class diagram for CellPath

classDiagram
  class CellPath {
    -notebook: Path
    -cell: str
    +__eq__(other: object) bool
    +__hash__() int
    +exists(*args: Any, **kwargs: Any) bool
    +relative_to(other: PathLike, *args: Any, **kwargs: Any) Self
    +notebook() Path
    +cell() str
    +is_cellpath(path: str) bool
    +get_notebookpath(path: str) Path
    +get_cellid(path: str) int
    +to_nodeid(path: str) str
    +patch_pytest_absolutepath() dict[tuple[ModuleType, str], FunctionType]
  }
  Path <|-- CellPath
  class Path {
  }
  CellPath ..> Path : notebook
Loading

File-Level Changes

Change Details Files
Refactor CellPath to use subscript format path/to/notebook.ipynb[Celln] instead of path/to/notebook.ipynb::Celln.
  • Update CellPath to use square brackets [] instead of double colons :: to denote cell IDs.
  • Update CellPath.is_cellpath to check for the new format.
  • Update CellPath.get_notebookpath and CellPath.get_cellid to parse the new format.
  • Add CellPath.to_nodeid to convert the new format to the old format for pytest node IDs.
  • Update tests to reflect the new CellPath format.
pytest_ipynb2/plugin.py
tests/test_execution.py
pytest_ipynb2/_cellpath.py
tests/test_collection.py
Implement command line argument handling for CellPaths.
  • Add pytest_load_initial_conftests hook to convert CellPaths passed as command line arguments to node IDs.
  • Add tests for running notebooks, cells, and functions from the command line.
pytest_ipynb2/plugin.py
tests/test_commandline.py
Monkeypatch pytest to handle CellPath and revert patches after session.
  • Patch _pytest.pathlib.absolutepath to handle CellPaths.
  • Store original functions in stash to revert later in pytest_sessionfinish.
  • Move patch_pytest_absolutepath to CellPath class.
  • Revert monkeypatches in pytest_sessionfinish.
pytest_ipynb2/plugin.py
pytest_ipynb2/_cellpath.py
Remove unnecessary conftest entry in tests.
  • Remove conftest="pytest_plugins = ['pytest_ipynb2.plugin']" from ExampleDirSpec in tests.
tests/test_execution.py
tests/test_collection.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

codecov bot commented Mar 9, 2025

Codecov Report

Attention: Patch coverage is 55.00000% with 45 lines in your changes missing coverage. Please review.

Project coverage is 71.91%. Comparing base (fbc42e8) to head (eb178b8).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pytest_ipynb2/_cellpath.py 50.72% 34 Missing ⚠️
pytest_ipynb2/plugin.py 57.69% 11 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##              main      #54       +/-   ##
============================================
- Coverage   100.00%   71.91%   -28.09%     
============================================
  Files            3        4        +1     
  Lines          345      349        +4     
  Branches        28       29        +1     
============================================
- Hits           345      251       -94     
- Misses           0       97       +97     
- Partials         0        1        +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @MusicalNinjaDad - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a helper function to construct ExampleDirSpec instances in tests to reduce duplication.
  • The new CellPath format is more standard and readable.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟡 Review instructions: 3 issues found
  • 🟡 Testing: 2 issues found
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


### Fixed

- Integration with vscode Test Explorer [#54][pr-54]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (typo): Typo: "vscode" should be "VS Code"

Consider using the official capitalization "VS Code" for consistency.

Suggested change
- Integration with vscode Test Explorer [#54][pr-54]
- Integration with VS Code Test Explorer [#54][pr-54]

item_type = type(item)
type_with_mixin = types.new_class(item_type.__name__, (CellPath.PytestItemMixin, item_type))
item.__class__ = type_with_mixin
yield item
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider using explicit inheritance with a wrapper factory instead of dynamically creating a new class in collect() to reduce cognitive overhead, and move monkey-patching logic to its own module with inline comments explaining why the patching is required to reduce indirection and complexity while preserving functionality

The general approach is good, but the dynamic re-blessing of items in collect() adds significant cognitive overhead. Consider extracting the wrapping into a small helper and using explicit inheritance instead of dynamically creating a new class.

For example, introduce a wrapper factory and refactor collect() like so:

def wrap_pytest_item(item: pytest.Function) -> pytest.Function:
    # Explicitly define a subclass using our mixin and the item's original type
    class WrappedItem(CellPath.PytestItemMixin, type(item)):
        pass
    item.__class__ = WrappedItem
    return item

Then, update collect() to delegate the wrapping:

def collect(self) -> Generator[pytest.Function, None, None]:
    for item in super().collect():
        yield wrap_pytest_item(item)

This makes the intent clear, isolates the dynamic modification in a small helper, and reduces in-line complexity while preserving functionality.

Additionally, consider:

  • Moving monkey-patching logic (i.e. patch_pytest_absolutepath) to its own module or function.
  • Adding concise inline comments about why the patching is required.

These changes keep the functionality intact while reducing the indirection and complexity.

"""The cell specifier (e.g. "Cell0")."""
return f"{CELL_PREFIX}{self.get_cellid(str(self))}"

@classmethod
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (review_instructions): The get_notebookpath and get_cellid methods could use EAFP instead of relying on string parsing

These methods parse strings assuming a specific format. Consider using try/except to handle cases where the string doesn't match the expected format, which would follow the EAFP principle.

Review instructions:

Path patterns: **/*.py, **/*.ipynb

Instructions:
Prefer EAFP to LBYL in most cases

@MusicalNinjaDad MusicalNinjaDad enabled auto-merge (squash) March 9, 2025 15:06
@MusicalNinjaDad MusicalNinjaDad merged commit acbd54b into main Mar 9, 2025
8 checks passed
@MusicalNinjaDad MusicalNinjaDad deleted the vscode branch March 9, 2025 15:07
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.

1 participant