Skip to content

Harden #301/#212/#295 regression tests + make AttributeDict generic#326

Open
wolph wants to merge 5 commits into
developfrom
harden-issue-tests-2
Open

Harden #301/#212/#295 regression tests + make AttributeDict generic#326
wolph wants to merge 5 commits into
developfrom
harden-issue-tests-2

Conversation

@wolph

@wolph wolph commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Locks the already-merged fixes for three open issues with integration-level tests, and upgrades AttributeDict to be generic over its value type.

Changes

  • stdout isnt doesn't unwraped when interupted #212tests/test_stream.py::test_redirect_stdout_unwrapped_after_keyboard_interrupt: subprocess test proving sys.stdout is unwrapped after a KeyboardInterrupt abandons a redirect_stdout iteration (process-global, so it needs a real child process).
  • Progress bar is duplicated when used both as a context manager and as an iterable wrapper #301tests/test_with.py::test_context_manager_and_iterable_reporter_widgets_no_duplicate: the reporter's exact widget set + a generator used as both context manager and iterable renders the completed bar exactly once.
  • Missing separating blank line option #295tests/test_terminal.py::test_redirect_blank_line_position: asserts the separating blank line sits between the clear sequence and the bar redraw (not merely "somewhere").
  • AttributeDictprogressbar/utils.py: dictdict[str, T], Generic[T], so homogeneous typed use (AttributeDict[int]) flows the real value type through __getattr__/__setattr__ and catches mis-typed assignment (pyright-verified). tests/test_utils.py::test_attribute_dict_generic_value_type.
  • Coveragetests/test_stream.py::test_wrap_logging_deduplicates_shared_handler: covers the shared-handler dedup continue in wrap_logging, restoring the 100% gate.

Verification (clean checkout)

  • 671 passed, 14 skipped; 100.00% coverage.
  • pyright progressbar: 0 errors. ruff check: clean.

Copilot AI review requested due to automatic review settings July 18, 2026 16:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces generic typing to AttributeDict and adds several regression tests covering stream redirection, logging deduplication, blank line positioning, and context manager usage. The review feedback suggests improving the subprocess test by propagating PYTHONPATH to ensure reliable imports, and refactoring the manual stream unwrapping loop to use the existing reset_wrapped_streams() helper.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread tests/test_stream.py
Comment on lines +513 to +515
result = subprocess.run(
[sys.executable, '-c', child], capture_output=True, text=True
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To ensure that the subprocess can reliably import the progressbar package across different test runners and environments (e.g., when the package is not installed globally or in editable mode but is present in sys.path), propagate the current sys.path via the PYTHONPATH environment variable.

Suggested change
result = subprocess.run(
[sys.executable, '-c', child], capture_output=True, text=True
)
env = os.environ.copy()
env["PYTHONPATH"] = os.path.pathsep.join(sys.path)
result = subprocess.run(
[sys.executable, "-c", child],
capture_output=True,
text=True,
env=env,
)

Comment thread tests/test_stream.py
Comment on lines +526 to +528
for _ in range(5):
progressbar.streams.unwrap(stderr=True, stdout=True)
progressbar.streams.unwrap_logging()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Instead of manually unwrapping the streams with a hardcoded loop, use the existing helper function reset_wrapped_streams() which is defined at the top of this file. This ensures consistent, robust, and clean reset of all wrapped streams across all tests.

    reset_wrapped_streams()

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a142850d8d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread progressbar/utils.py


class AttributeDict(dict):
class AttributeDict(dict[str, T], typing.Generic[T]):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep generic metadata out of AttributeDict contents

When a caller instantiates the new runtime generic form (AttributeDict[int]()), typing.Generic writes __orig_class__ onto the instance. Because this class routes every __setattr__ into self[name], that metadata becomes a real dictionary entry, so an empty typed AttributeDict has length 1 and iterates/serializes with a spurious __orig_class__ key. The added test only annotates an unparameterized constructor, so it misses the advertised usage; special-case this internal attribute or avoid storing all real attributes as dict items.

Useful? React with 👍 / 👎.

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.

2 participants