diff --git a/src/con_duct/__init__.py b/src/con_duct/__init__.py index 3e0116c5..e2ab41c6 100644 --- a/src/con_duct/__init__.py +++ b/src/con_duct/__init__.py @@ -1,3 +1,6 @@ -from importlib.metadata import version +from ._duct_main import __version__, execute -__version__ = version("con-duct") +__all__ = [ + "execute", + "__version__", +] diff --git a/src/con_duct/duct_main.py b/src/con_duct/_duct_main.py old mode 100755 new mode 100644 similarity index 98% rename from src/con_duct/duct_main.py rename to src/con_duct/_duct_main.py index 385f42fb..8c2623ee --- a/src/con_duct/duct_main.py +++ b/src/con_duct/_duct_main.py @@ -1,4 +1,5 @@ from __future__ import annotations +from importlib.metadata import version import logging import os import signal @@ -9,7 +10,9 @@ from con_duct._models import LogPaths, Outputs, RecordTypes, SessionMode from con_duct._output import TailPipe, prepare_outputs, remove_files, safe_close_files from con_duct._signals import SigIntHandler -from con_duct._tracker import Report, __version__, monitor_process +from con_duct._tracker import Report, monitor_process + +__version__ = version("con-duct") lgr = logging.getLogger("con-duct") diff --git a/src/con_duct/cli.py b/src/con_duct/cli.py index 29584ca5..2de8b42d 100644 --- a/src/con_duct/cli.py +++ b/src/con_duct/cli.py @@ -7,9 +7,9 @@ import textwrap from typing import List, Optional from con_duct import __version__ +from con_duct._duct_main import DUCT_OUTPUT_PREFIX, EXECUTION_SUMMARY_FORMAT +from con_duct._duct_main import execute as duct_execute from con_duct._models import Outputs, RecordTypes, SessionMode -from con_duct.duct_main import DUCT_OUTPUT_PREFIX, EXECUTION_SUMMARY_FORMAT -from con_duct.duct_main import execute as duct_execute from con_duct.ls import LS_FIELD_CHOICES, ls from con_duct.plot import matplotlib_plot from con_duct.pprint_json import pprint_json diff --git a/src/con_duct/ls.py b/src/con_duct/ls.py index 37b21e8c..403eed6a 100644 --- a/src/con_duct/ls.py +++ b/src/con_duct/ls.py @@ -7,9 +7,9 @@ from types import ModuleType from typing import Any, Dict, List, Optional from con_duct._constants import __schema_version__ +from con_duct._duct_main import DUCT_OUTPUT_PREFIX from con_duct._formatter import SummaryFormatter from con_duct._utils import parse_version -from con_duct.duct_main import DUCT_OUTPUT_PREFIX from con_duct.json_utils import is_info_file try: diff --git a/test/conftest.py b/test/conftest.py index dcdc48ed..04765bb3 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -31,7 +31,7 @@ def reset_logger_state() -> Generator: or log_level="NONE", which affects subsequent tests. This fixture ensures the logger is reset to default state after each test. """ - import con_duct.duct_main as main_module + import con_duct._duct_main as main_module yield diff --git a/test/duct_main/test_aggregation.py b/test/duct_main/test_aggregation.py index 5b9857c9..fb6925ca 100644 --- a/test/duct_main/test_aggregation.py +++ b/test/duct_main/test_aggregation.py @@ -4,9 +4,9 @@ from typing import cast from unittest import mock import pytest +from con_duct._duct_main import EXECUTION_SUMMARY_FORMAT from con_duct._models import ProcessStats, Sample from con_duct._tracker import Report -from con_duct.duct_main import EXECUTION_SUMMARY_FORMAT stat0 = ProcessStats( pcpu=0.0, @@ -63,7 +63,7 @@ ) -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_num_samples_increment(mock_log_paths: mock.MagicMock) -> None: ex0 = Sample() ex0.add_pid(1, deepcopy(stat1)) @@ -89,7 +89,7 @@ def test_aggregation_num_samples_increment(mock_log_paths: mock.MagicMock) -> No assert report.full_run_stats.averages.num_samples == 3 -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_single_sample_sanity(mock_log_paths: mock.MagicMock) -> None: ex0 = Sample() ex0.add_pid(0, deepcopy(stat0)) @@ -126,7 +126,7 @@ def test_aggregation_single_sample_sanity(mock_log_paths: mock.MagicMock) -> Non @pytest.mark.parametrize("stat", [stat0, stat1, stat2, stat_big]) -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_single_stat_multiple_samples_sanity( mock_log_paths: mock.MagicMock, stat: ProcessStats ) -> None: @@ -173,7 +173,7 @@ def test_aggregation_single_stat_multiple_samples_sanity( assert report.current_sample.averages.pcpu == report.current_sample.total_pcpu -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_averages(mock_log_paths: mock.MagicMock) -> None: sample0 = Sample() sample0.add_pid(1, deepcopy(stat0)) @@ -243,7 +243,7 @@ def test_aggregation_averages(mock_log_paths: mock.MagicMock) -> None: ) -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_current_ave_diverges_from_total_ave( mock_log_paths: mock.MagicMock, ) -> None: @@ -313,7 +313,7 @@ def test_aggregation_current_ave_diverges_from_total_ave( @pytest.mark.parametrize("stat", [stat0, stat1, stat2, stat_big]) -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_many_samples( mock_log_paths: mock.MagicMock, stat: ProcessStats ) -> None: @@ -358,7 +358,7 @@ def test_aggregation_many_samples( assert report.full_run_stats.averages.pcpu == (stat.pcpu * 100 + stat2.pcpu) / 101.0 -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_sample_no_pids(mock_log_paths: mock.MagicMock) -> None: sample0 = Sample() mock_log_paths.prefix = "mock_prefix" @@ -372,7 +372,7 @@ def test_aggregation_sample_no_pids(mock_log_paths: mock.MagicMock) -> None: report.update_from_sample(sample0) -@mock.patch("con_duct.duct_main.LogPaths") +@mock.patch("con_duct._duct_main.LogPaths") def test_aggregation_no_false_peak(mock_log_paths: mock.MagicMock) -> None: sample1 = Sample() sample2 = Sample() diff --git a/test/duct_main/test_duct_utils.py b/test/duct_main/test_duct_utils.py index 0c6e0285..c25a4991 100644 --- a/test/duct_main/test_duct_utils.py +++ b/test/duct_main/test_duct_utils.py @@ -1,4 +1,4 @@ -"""Tests for utility functions in duct_main.py""" +"""Tests for utility functions in _duct_main.py""" import pytest from con_duct._utils import assert_num diff --git a/test/duct_main/test_execution.py b/test/duct_main/test_execution.py index 5b264a36..7c7f0805 100644 --- a/test/duct_main/test_execution.py +++ b/test/duct_main/test_execution.py @@ -10,7 +10,7 @@ from time import sleep, time import pytest from utils import assert_files, run_duct_command -from con_duct import duct_main +from con_duct import _duct_main from con_duct._constants import SUFFIXES from con_duct._models import Outputs @@ -310,7 +310,7 @@ def test_signal_kill( def test_duct_as_executable(temp_output_dir: str) -> None: ps_command = [ sys.executable, - duct_main.__file__, + _duct_main.__file__, "-p", temp_output_dir, "-q", diff --git a/test/duct_main/test_log_paths.py b/test/duct_main/test_log_paths.py index 9539efc7..86113756 100644 --- a/test/duct_main/test_log_paths.py +++ b/test/duct_main/test_log_paths.py @@ -28,8 +28,8 @@ def test_log_paths_pid_prefix() -> None: "/abs/path/", ], ) -@patch("con_duct.duct_main.os.makedirs") -@patch("con_duct.duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") @patch("builtins.open") def test_prepare_dir_paths_available( _mock_open: MagicMock, mock_exists: MagicMock, mock_mkdir: MagicMock, path: str @@ -48,8 +48,8 @@ def test_prepare_dir_paths_available( "/abs/path/pre_", ], ) -@patch("con_duct.duct_main.os.path.exists") -@patch("con_duct.duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") @patch("builtins.open") def test_prefix_with_filepart_and_directory_part( mock_open: MagicMock, mock_mkdir: MagicMock, mock_exists: MagicMock, path: str @@ -62,8 +62,8 @@ def test_prefix_with_filepart_and_directory_part( mock_open.assert_has_calls(expected_calls, any_order=True) -@patch("con_duct.duct_main.os.path.exists") -@patch("con_duct.duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") @patch("builtins.open") def test_prefix_with_filepart_only( mock_open: MagicMock, mock_mkdir: MagicMock, mock_exists: MagicMock @@ -76,8 +76,8 @@ def test_prefix_with_filepart_only( mock_open.assert_has_calls(expected_calls, any_order=True) -@patch("con_duct.duct_main.os.path.exists") -@patch("con_duct.duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") @patch("builtins.open") def test_prepare_file_paths_available_all( mock_open: MagicMock, _mock_mkdir: MagicMock, mock_exists: MagicMock @@ -90,8 +90,8 @@ def test_prepare_file_paths_available_all( mock_open.assert_has_calls(expected_calls, any_order=True) -@patch("con_duct.duct_main.os.path.exists") -@patch("con_duct.duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") @patch("builtins.open") def test_prepare_file_paths_available_stdout( mock_open: MagicMock, _mock_mkdir: MagicMock, mock_exists: MagicMock @@ -106,8 +106,8 @@ def test_prepare_file_paths_available_stdout( mock_open.assert_has_calls(expected_calls, any_order=True) -@patch("con_duct.duct_main.os.path.exists") -@patch("con_duct.duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") @patch("builtins.open") def test_prepare_file_paths_available_stderr( mock_open: MagicMock, _mock_mkdir: MagicMock, mock_exists: MagicMock @@ -122,8 +122,8 @@ def test_prepare_file_paths_available_stderr( mock_open.assert_has_calls(expected_calls, any_order=True) -@patch("con_duct.duct_main.os.path.exists") -@patch("con_duct.duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") @patch("builtins.open") def test_prepare_file_paths_available_no_streams( mock_open: MagicMock, _mock_mkdir: MagicMock, mock_exists: MagicMock @@ -139,8 +139,8 @@ def test_prepare_file_paths_available_no_streams( mock_open.assert_has_calls(expected_calls, any_order=True) -@patch("con_duct.duct_main.os.makedirs") -@patch("con_duct.duct_main.os.path.exists") +@patch("con_duct._duct_main.os.makedirs") +@patch("con_duct._duct_main.os.path.exists") @patch("builtins.open") def test_prepare_paths_not_available_no_clobber( mock_open: MagicMock, mock_exists: MagicMock, mock_mkdir: MagicMock diff --git a/test/duct_main/test_report.py b/test/duct_main/test_report.py index 52377725..c4cb9206 100644 --- a/test/duct_main/test_report.py +++ b/test/duct_main/test_report.py @@ -6,9 +6,9 @@ import subprocess from unittest import mock import pytest +from con_duct._duct_main import EXECUTION_SUMMARY_FORMAT from con_duct._models import Averages, ProcessStats, Sample from con_duct._tracker import Report -from con_duct.duct_main import EXECUTION_SUMMARY_FORMAT stat0 = ProcessStats( pcpu=0.0, diff --git a/test/test_formatter.py b/test/test_formatter.py index 0576d090..c8e40d49 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -8,8 +8,8 @@ RED_START = SummaryFormatter.COLOR_SEQ % SummaryFormatter.RED -@mock.patch("con_duct.duct_main.LogPaths") -@mock.patch("con_duct.duct_main.subprocess.Popen") +@mock.patch("con_duct._duct_main.LogPaths") +@mock.patch("con_duct._duct_main.subprocess.Popen") def test_execution_summary_formatted_wall_clock_time_nan( mock_popen: mock.MagicMock, mock_log_paths: mock.MagicMock ) -> None: @@ -32,8 +32,8 @@ def test_execution_summary_formatted_wall_clock_time_nan( assert "wall clock time: nan" in report.execution_summary_formatted.lower() -@mock.patch("con_duct.duct_main.LogPaths") -@mock.patch("con_duct.duct_main.subprocess.Popen") +@mock.patch("con_duct._duct_main.LogPaths") +@mock.patch("con_duct._duct_main.subprocess.Popen") def test_execution_summary_formatted_wall_clock_time_rounded( mock_popen: mock.MagicMock, mock_log_paths: mock.MagicMock ) -> None: @@ -303,8 +303,8 @@ def test_summary_formatter_N_e2e_colors() -> None: assert n_zero_applied == f"test {RED_START}-{formatter.RESET_SEQ}" -@mock.patch("con_duct.duct_main.LogPaths") -@mock.patch("con_duct.duct_main.subprocess.Popen") +@mock.patch("con_duct._duct_main.LogPaths") +@mock.patch("con_duct._duct_main.subprocess.Popen") @pytest.mark.parametrize("colors", [True, False]) def test_execution_summary_formatted_wall_clock_time_nowvalid( mock_popen: mock.MagicMock, mock_log_paths: mock.MagicMock, colors: bool diff --git a/test/utils.py b/test/utils.py index 2cc04f83..d5ec9bef 100644 --- a/test/utils.py +++ b/test/utils.py @@ -14,9 +14,9 @@ def run_duct_command(cli_args: list[str], **kwargs: Any) -> int: Returns: Exit code from the executed command """ + from con_duct._duct_main import DUCT_OUTPUT_PREFIX, EXECUTION_SUMMARY_FORMAT + from con_duct._duct_main import execute as duct_execute from con_duct._models import Outputs, RecordTypes, SessionMode - from con_duct.duct_main import DUCT_OUTPUT_PREFIX, EXECUTION_SUMMARY_FORMAT - from con_duct.duct_main import execute as duct_execute command = cli_args[0] command_args = cli_args[1:] if len(cli_args) > 1 else []