Skip to content

Conversation

@asmacdo
Copy link
Member

@asmacdo asmacdo commented Jan 23, 2026

Summary

Completes the module extraction from duct_main.py as outlined in #372.

Extracted modules:

  • _formatter.py - SummaryFormatter class
  • _signals.py - SigIntHandler
  • _sampling.py - Platform-specific process sampling
  • _output.py - TailPipe, output preparation, file cleanup
  • _tracker.py - Report class and monitor_process function

Result:

  • duct_main.py reduced from ~600 lines to ~180 lines
  • Now contains only the execute() orchestration function and two constants

Deferred:

🤖 Generated with Claude Code

asmacdo and others added 18 commits January 23, 2026 13:02
Move ENV_PREFIXES and SUFFIXES to dedicated _constants module.
Remove unused DEFAULT_LOG_LEVEL.

Part of #372

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: extract constants to _constants.py
Move enums (Outputs, RecordTypes, SessionMode) and dataclasses
(SystemInfo, ProcessStats, LogPaths, Averages, Sample) to _models.py.
Create _utils.py with assert_num helper.

Part of #372

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move parse_version from utils.py to _utils.py and remove utils.py.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: extract models and enums to _models.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: extract SummaryFormatter to _formatter.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: extract SigIntHandler to _signals.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: extract sampling functions to _sampling.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: extract IO utilities to _output.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
refactor: extract Report and monitor_process to _tracker.py
This file is no longer directly executable - it's a module imported
by the CLI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 95.12195% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.81%. Comparing base (c491bb4) to head (2bff9f5).
⚠️ Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
src/con_duct/_signals.py 48.00% 13 Missing ⚠️
src/con_duct/_output.py 92.30% 4 Missing and 2 partials ⚠️
src/con_duct/_tracker.py 96.99% 2 Missing and 2 partials ⚠️
src/con_duct/_models.py 98.32% 2 Missing and 1 partial ⚠️
src/con_duct/_sampling.py 95.91% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #385      +/-   ##
==========================================
+ Coverage   91.38%   91.81%   +0.43%     
==========================================
  Files           8       15       +7     
  Lines        1056     1112      +56     
  Branches      138      138              
==========================================
+ Hits          965     1021      +56     
  Misses         69       69              
  Partials       22       22              

☔ 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.

@asmacdo asmacdo marked this pull request as ready for review January 24, 2026 00:12
Copilot AI review requested due to automatic review settings January 24, 2026 00:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR successfully refactors duct_main.py by extracting code into smaller, focused modules as outlined in issue #372. The refactoring reduces duct_main.py from approximately 600 lines to 180 lines, improving maintainability and code organization.

Changes:

  • Extracted 8 new private modules: _constants.py, _models.py, _utils.py, _formatter.py, _signals.py, _sampling.py, _output.py, and _tracker.py
  • Updated imports across all source and test files to reference the new module structure
  • Maintained DUCT_OUTPUT_PREFIX and EXECUTION_SUMMARY_FORMAT in duct_main.py as noted in the deferred work section

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/con_duct/_constants.py New module containing __schema_version__, ENV_PREFIXES, and SUFFIXES constants
src/con_duct/_models.py New module with data models (Enums: Outputs, RecordTypes, SessionMode; Dataclasses: SystemInfo, ProcessStats, LogPaths, Averages, Sample)
src/con_duct/_utils.py New module with utility functions (assert_num, parse_version)
src/con_duct/_formatter.py New module containing SummaryFormatter class for output formatting
src/con_duct/_signals.py New module with SigIntHandler for signal handling
src/con_duct/_sampling.py New module with platform-specific process sampling functions
src/con_duct/_output.py New module with TailPipe class and I/O utility functions
src/con_duct/_tracker.py New module containing Report class, monitor_process function, and __version__
src/con_duct/duct_main.py Reduced to orchestration function execute() and two constants, imports from new modules
src/con_duct/cli.py Updated imports to reference new module locations
src/con_duct/ls.py Updated imports to reference new module locations
src/con_duct/json_utils.py Updated imports to reference _constants module
src/con_duct/pprint_json.py Updated imports to reference _formatter module
test/*.py Updated all test imports to reference new module locations

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

for f in file_list:
try:
f.close()
except Exception:
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

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

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except Exception:
except Exception:
# Best-effort close: ignore errors (e.g., already closed or invalid objects).

Copilot uses AI. Check for mistakes.
from pathlib import Path
from utils import run_duct_command
from con_duct.duct_main import SUFFIXES
from con_duct._constants import SUFFIXES
Copy link
Contributor

Choose a reason for hiding this comment

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

Well, this is the sort of thing that is not great (but we can fix in follow-up focusing on import control)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep I imagine constants should be public, but I figured for this approach, lets start off a bit ham-handed, and make everything private so we can be minimal as we transition to library usage.


import pytest
from con_duct.duct_main import assert_num
from con_duct._utils import assert_num
Copy link
Contributor

Choose a reason for hiding this comment

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

Testing helpers generally fall under a .testing public module

Can fix in follow up

Copy link
Member Author

Choose a reason for hiding this comment

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

this is used outside of tests also, but im open to move later.

from con_duct import duct_main
from con_duct.duct_main import SUFFIXES, Outputs
from con_duct._constants import SUFFIXES
from con_duct._models import Outputs
Copy link
Contributor

Choose a reason for hiding this comment

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

Basically, anything you import from the main package like this is a good example of something that should be publicly exposed either at root level or via some public submodule

Tests like this help indicate what might be intended to be exposed

@CodyCBakerPhD
Copy link
Contributor

Overall LGTM - some discussion points for the importing specific followup above

@asmacdo I assume you have tried out this branch in practice (not just tests) and found it working to your liking?

Left my approval FWIW (have read-only permissions so doesn't mean much here)

@CodyCBakerPhD
Copy link
Contributor

Keep in mind one of the great benefits of privatizing this kind of stuff (after fixing import structure in follow up) is after that you can feel free to alter the file/directory structure freely at will without worrying about breaking anything

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@asmacdo
Copy link
Member Author

asmacdo commented Jan 28, 2026

I have tested locally, and it works. This isn't perfect, but I think it provides a nice structure to build on, so I'll merge after CI comes back green.

@asmacdo asmacdo merged commit 3756590 into main Jan 28, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor duct_main.py into smaller modules

3 participants