diff --git a/dodo.py b/dodo.py index 9d193c9b..ca219998 100644 --- a/dodo.py +++ b/dodo.py @@ -28,7 +28,6 @@ def task_localize(): def task_properties(): - """ For all languages: a) Combines all existing properties files for a language into a single file called 'combined.tmp' and b) removes duplicates while preserving the original order of properties @@ -377,7 +376,6 @@ def move_strings(): def task_version(): - """Generates a metadata info file with current version to be bundled by pyinstaller""" def write_for_pyinstaller(): @@ -459,7 +457,6 @@ def uniquify_file(filename): def task_clean_all(): - """remove all generated files such as .po, .out, and pdf, csv etc that are not in the assets folder""" def clean_output_files(): diff --git a/pyproject.toml b/pyproject.toml index 0456f3c7..dc379cf2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,8 +10,7 @@ packages = ["tabcmd"] tabcmd = ["tabcmd.locales/**/*.mo"] [tool.black] line-length = 120 -required-version = 22 -target-version = ['py310', 'py311'] +target-version = ['py310', 'py311', 'py312', 'py313', 'py314'] extend-exclude = '^/bin/*' [tool.mypy] check_untyped_defs = true @@ -53,9 +52,9 @@ dependencies = [ ] [project.optional-dependencies] test = [ - "black>=22,<23", + "black==26.5.1", "mock", - "mypy", + "mypy==2.3.0", "pytest>=7.0", "pytest-cov", "pytest-order", diff --git a/tabcmd/execution/global_options.py b/tabcmd/execution/global_options.py index 1a24133c..af969c3c 100644 --- a/tabcmd/execution/global_options.py +++ b/tabcmd/execution/global_options.py @@ -25,6 +25,7 @@ """ + # argparse does case-sensitive comparisons of string inputs by default # I want the user to be able to enter e.g. "viewer" and have it accepted as "Viewer" # https://stackoverflow.com/questions/56838004/ @@ -123,6 +124,7 @@ def set_encryption_option(parser): # item arguments: datasource, workbook, project, url ... + # Matching classic tabcmd: # for some reason in parser.project, publish-samples it uses -n for destination project name # for publish it uses -r for destination project name diff --git a/tabcmd/execution/localize.py b/tabcmd/execution/localize.py index cc8baf1c..07e0c4e8 100644 --- a/tabcmd/execution/localize.py +++ b/tabcmd/execution/localize.py @@ -51,6 +51,8 @@ def set_client_locale(lang: str = "", logger=None) -> Optional[Callable]: """Get absolute path to resource, works for unbundled (e.g dev) and when bundled by PyInstaller""" + + # https://stackoverflow.com/questions/7674790/bundling-data-files-with-pyinstaller-onefile/13790741#13790741 def define_locale_dir(logger): diff --git a/tabcmd/execution/logger_config.py b/tabcmd/execution/logger_config.py index 72216fa7..5b470160 100644 --- a/tabcmd/execution/logger_config.py +++ b/tabcmd/execution/logger_config.py @@ -14,6 +14,7 @@ logging.DEBUG: "%(asctime)s %(levelname)-5s: (%(name)-10s %(filename)-10s: %(lineno)d): %(message)-30s", } + # https://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility def add_log_level(level_name, level_num, method_name=None): if not method_name: diff --git a/tabcmd/version.py b/tabcmd/version.py index 3b540282..febb4e32 100644 --- a/tabcmd/version.py +++ b/tabcmd/version.py @@ -7,6 +7,8 @@ # importlib.metadata is unavailable in PyInstaller bundles; fall back to the # _version.py file that setuptools_scm writes at build time. try: - from tabcmd._version import version + from tabcmd._version import version as _pyinstaller_version + + version = _pyinstaller_version except ImportError: version = "0.0" diff --git a/tests/assets/mock_data.py b/tests/assets/mock_data.py index e7d3468c..3b37f4f1 100644 --- a/tests/assets/mock_data.py +++ b/tests/assets/mock_data.py @@ -93,6 +93,7 @@ def set_up_mock_server(mock_session): mock_server.any_item_type = getter mock_server.flows = getter mock_server.groups = getter + # Ensure type name contains 'Projects' for filtering heuristics class ProjectsEndpoint: def __init__(self, ret): diff --git a/tests/commands/test_listing_commands.py b/tests/commands/test_listing_commands.py index 5d638cb9..ffe51fa3 100644 --- a/tests/commands/test_listing_commands.py +++ b/tests/commands/test_listing_commands.py @@ -96,6 +96,7 @@ class ListCommandFunctionalTests(unittest.TestCase): @patch("tabcmd.execution.logger_config.log") def test_show_header_with_all_options(self, mock_log, mock_session, mock_translate): """Test header generation with all display options enabled""" + # Mock the translation function to return the actual English strings def translate_side_effect(key): translations = { diff --git a/tests/e2e/online_tests.py b/tests/e2e/online_tests.py index 741af663..96ff7fcd 100644 --- a/tests/e2e/online_tests.py +++ b/tests/e2e/online_tests.py @@ -15,7 +15,6 @@ from tests.e2e import setup_e2e - # to run this suite # pytest -q tests/e2e/online_tests.py # you can either run setup with a stored credentials file, or simply log in diff --git a/tests/e2e/tests_integration.py b/tests/e2e/tests_integration.py index 136866b3..6903df93 100644 --- a/tests/e2e/tests_integration.py +++ b/tests/e2e/tests_integration.py @@ -6,7 +6,6 @@ from tabcmd.commands.server import Server from tabcmd.execution.logger_config import log - try: from tests.e2e import credentials # type: ignore except ImportError: @@ -16,6 +15,7 @@ logging.disable(logging.ERROR) logger = log("tests_integration", "info") + # these are integration tests because they don't just run a command, they call interior methods # pytest -v tests/e2e/integration_tests.py class E2EJsonTests(unittest.TestCase): diff --git a/tests/test_main.py b/tests/test_main.py index f2c11d33..775db015 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -49,8 +49,7 @@ def test_python_m_tabcmd_help_subcommand_exits_zero(self): def test_import_error_exits_one(self): # Inject a broken tabcmd.tabcmd into sys.modules before running __main__, # so the ImportError handler is exercised without relying on sys.path ordering. - script = textwrap.dedent( - """\ + script = textwrap.dedent("""\ import sys class _BrokenTabcmd: def __getattr__(self, _): @@ -58,8 +57,7 @@ def __getattr__(self, _): sys.modules["tabcmd.tabcmd"] = _BrokenTabcmd() import runpy runpy.run_module("tabcmd", run_name="__main__") - """ - ) + """) with tempfile.TemporaryDirectory() as tmpdir: script_path = os.path.join(tmpdir, "run.py") with open(script_path, "w") as f: