From f0e2a8262111b0e28190997bf15f3a32e8bd141d Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:20:32 +0000 Subject: [PATCH 01/30] file-org-workflows: add github workflow for testing --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b63712a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ + +name: Python CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r Beginner/file_organiser/requirements.txt + pip install ruff black mypy + + - name: Lint with ruff + run: ruff check Beginner/file_organiser/src Beginner/file_organiser/tests + + - name: Format with black + run: black --check Beginner/file_organiser/src Beginner/file_organiser/tests + + - name: Typecheck with mypy + run: mypy Beginner/file_organiser/src + + - name: Test with pytest + run: pytest Beginner/file_organiser/tests From afe3a62638ada1baa66d21dca2a215d91e174d06 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:25:20 +0000 Subject: [PATCH 02/30] file-org-workflows: trigger workflow on all branches --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b63712a..0e409e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,9 +3,9 @@ name: Python CI on: push: - branches: [ "main" ] + branches: [ "**" ] pull_request: - branches: [ "main" ] + branches: [ "**" ] jobs: build: From 85fa8a8bd190a0e7fb9f06b30c7bb5534b97e04d Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:28:43 +0000 Subject: [PATCH 03/30] file-org-workflows: use python 3.13 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e409e8..6aef748 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: '3.11' + python-version: '3.13' - name: Install dependencies run: | From b097cb7686540d12db9dd6ac488a32c075bf4255 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:31:32 +0000 Subject: [PATCH 04/30] file-org-workflows: allow lint to fail --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6aef748..248fcbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,7 @@ jobs: pip install ruff black mypy - name: Lint with ruff + continue-on-error: true run: ruff check Beginner/file_organiser/src Beginner/file_organiser/tests - name: Format with black From 69926b9ffbd81a456c988e87bf3cce0390c10217 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:37:38 +0000 Subject: [PATCH 05/30] file-org-workflows: remove main expected return --- Beginner/file_organiser/src/file_organiser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Beginner/file_organiser/src/file_organiser.py b/Beginner/file_organiser/src/file_organiser.py index 463ca9f..aec7656 100644 --- a/Beginner/file_organiser/src/file_organiser.py +++ b/Beginner/file_organiser/src/file_organiser.py @@ -67,7 +67,7 @@ def parse_args(argv=None): return ap.parse_args(argv) -def main(argv=None) -> int: +def main(argv=None): args = parse_args(argv) if args.file: file_type = get_type(args.file) From bd43921b5f0d9b2b27daaff4ac67b4d3e7e5a7e1 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:41:45 +0000 Subject: [PATCH 06/30] file-org-workflows: add type hint to counts variable --- Beginner/file_organiser/src/file_organiser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Beginner/file_organiser/src/file_organiser.py b/Beginner/file_organiser/src/file_organiser.py index aec7656..33756c5 100644 --- a/Beginner/file_organiser/src/file_organiser.py +++ b/Beginner/file_organiser/src/file_organiser.py @@ -34,7 +34,7 @@ def get_files(path: Path | str, recursive=False): # This fuction calls the above 2 fuctions, to grab a list of files, and then fetching the file types, saving within a Counter def process_files(path: Path | str, recursive=False): - counts = Counter() + counts: Counter[str] = Counter() for f in track(get_files(path, recursive), description="Working...."): try: file_type = get_type(f) From fe0246dbd0b9840bb42d0cd63ca2e4ae5c69334c Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:48:13 +0000 Subject: [PATCH 07/30] file-org-workflows: fix failing tests by using tmp_path --- .../tests/unit/test_file_organiser.py | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Beginner/file_organiser/tests/unit/test_file_organiser.py b/Beginner/file_organiser/tests/unit/test_file_organiser.py index fd1f777..c9432ee 100644 --- a/Beginner/file_organiser/tests/unit/test_file_organiser.py +++ b/Beginner/file_organiser/tests/unit/test_file_organiser.py @@ -6,8 +6,9 @@ # Test main with args -def test_path(): - amount = main(["/mnt/c/Users/Adam/Desktop/adhd/"]) +def test_path(tmp_path): + (tmp_path / "file1.txt").touch() + amount = main([str(tmp_path)]) assert amount > 0 @@ -21,18 +22,22 @@ def test_no_path_recursive(): assert amount > 0 -def test_file_not_found(): +def test_file_not_found(tmp_path): with pytest.raises(FileNotFoundError, match="does not exist"): - list(get_files("/tmp/file-org/not-here")) + list(get_files(tmp_path / "not-here")) -def test_not_dir(): +def test_not_dir(tmp_path): + file = tmp_path / "text.txt" + file.touch() with pytest.raises(NotADirectoryError, match="is not a directory"): - list(main(["/tmp/file-org/text.txt"])) + list(main([str(file)])) -def test_with_file(): - file_type = main(["--file", "/mnt/c/Users/Adam/Desktop/adhd/20250820_160657.jpg"]) +def test_with_file(tmp_path): + fake_jpeg = tmp_path / "test.jpg" + fake_jpeg.write_bytes(b'\xff\xd8\xff\xe0') + file_type = main(["--file", str(fake_jpeg)]) assert file_type == "image/jpeg" @@ -80,15 +85,17 @@ def test_process_files_recursive(tmp_path): # Test get_type -def test_get_type_image(): - type = get_type("/mnt/c/Users/Adam/Desktop/adhd/20250820_160657.jpg") +def test_get_type_image(tmp_path): + fake_jpeg = tmp_path / "test.jpg" + fake_jpeg.write_bytes(b'\xff\xd8\xff\xe0') + type = get_type(str(fake_jpeg)) assert type == "image/jpeg" -def test_get_type_with_temp_file(): +def test_get_type_with_temp_file(tmp_path): # Create a dummy txt file txt_content = b"This is a dummy text file." - txt_file = "/tmp/dummy.txt" + txt_file = tmp_path / "dummy.txt" with open(txt_file, "wb") as f: f.write(txt_content) # test with get_type From 8ad1193ec8a3ed524eca69c25872526f3da72872 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:49:20 +0000 Subject: [PATCH 08/30] file-org-workflows: black fixes --- Beginner/file_organiser/tests/unit/test_file_organiser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Beginner/file_organiser/tests/unit/test_file_organiser.py b/Beginner/file_organiser/tests/unit/test_file_organiser.py index c9432ee..a6b758b 100644 --- a/Beginner/file_organiser/tests/unit/test_file_organiser.py +++ b/Beginner/file_organiser/tests/unit/test_file_organiser.py @@ -36,7 +36,7 @@ def test_not_dir(tmp_path): def test_with_file(tmp_path): fake_jpeg = tmp_path / "test.jpg" - fake_jpeg.write_bytes(b'\xff\xd8\xff\xe0') + fake_jpeg.write_bytes(b"\xff\xd8\xff\xe0") file_type = main(["--file", str(fake_jpeg)]) assert file_type == "image/jpeg" @@ -87,7 +87,7 @@ def test_process_files_recursive(tmp_path): # Test get_type def test_get_type_image(tmp_path): fake_jpeg = tmp_path / "test.jpg" - fake_jpeg.write_bytes(b'\xff\xd8\xff\xe0') + fake_jpeg.write_bytes(b"\xff\xd8\xff\xe0") type = get_type(str(fake_jpeg)) assert type == "image/jpeg" From 7dd91b150f1f1110a36cc594a090688e6cdcec0b Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Wed, 29 Oct 2025 22:52:41 +0000 Subject: [PATCH 09/30] file-org-workflows: add ruff and ruff fixes --- Beginner/file_organiser/pyproject.toml | 3 +- .../tests/unit/test_file_organiser.py | 2 +- Beginner/file_organiser/uv.lock | 28 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Beginner/file_organiser/pyproject.toml b/Beginner/file_organiser/pyproject.toml index 16da9e9..02bfbf2 100644 --- a/Beginner/file_organiser/pyproject.toml +++ b/Beginner/file_organiser/pyproject.toml @@ -26,4 +26,5 @@ dependencies = [ "pytest>=8.4.2", "python-magic>=0.4.27", "rich>=14.2.0", -] \ No newline at end of file + "ruff>=0.14.2", +] diff --git a/Beginner/file_organiser/tests/unit/test_file_organiser.py b/Beginner/file_organiser/tests/unit/test_file_organiser.py index a6b758b..4dcc82b 100644 --- a/Beginner/file_organiser/tests/unit/test_file_organiser.py +++ b/Beginner/file_organiser/tests/unit/test_file_organiser.py @@ -2,7 +2,7 @@ import pytest -from file_organiser import main, get_files, get_type, process_files +from file_organiser import get_files, get_type, main, process_files # Test main with args diff --git a/Beginner/file_organiser/uv.lock b/Beginner/file_organiser/uv.lock index eba1849..1560110 100644 --- a/Beginner/file_organiser/uv.lock +++ b/Beginner/file_organiser/uv.lock @@ -19,6 +19,7 @@ dependencies = [ { name = "pytest" }, { name = "python-magic" }, { name = "rich" }, + { name = "ruff" }, ] [package.metadata] @@ -26,6 +27,7 @@ requires-dist = [ { name = "pytest", specifier = ">=8.4.2" }, { name = "python-magic", specifier = ">=0.4.27" }, { name = "rich", specifier = ">=14.2.0" }, + { name = "ruff", specifier = ">=0.14.2" }, ] [[package]] @@ -122,3 +124,29 @@ sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7b wheels = [ { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, ] + +[[package]] +name = "ruff" +version = "0.14.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/34/8218a19b2055b80601e8fd201ec723c74c7fe1ca06d525a43ed07b6d8e85/ruff-0.14.2.tar.gz", hash = "sha256:98da787668f239313d9c902ca7c523fe11b8ec3f39345553a51b25abc4629c96", size = 5539663, upload-time = "2025-10-23T19:37:00.956Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/dd/23eb2db5ad9acae7c845700493b72d3ae214dce0b226f27df89216110f2b/ruff-0.14.2-py3-none-linux_armv6l.whl", hash = "sha256:7cbe4e593505bdec5884c2d0a4d791a90301bc23e49a6b1eb642dd85ef9c64f1", size = 12533390, upload-time = "2025-10-23T19:36:18.044Z" }, + { url = "https://files.pythonhosted.org/packages/5a/8c/5f9acff43ddcf3f85130d0146d0477e28ccecc495f9f684f8f7119b74c0d/ruff-0.14.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8d54b561729cee92f8d89c316ad7a3f9705533f5903b042399b6ae0ddfc62e11", size = 12887187, upload-time = "2025-10-23T19:36:22.664Z" }, + { url = "https://files.pythonhosted.org/packages/99/fa/047646491479074029665022e9f3dc6f0515797f40a4b6014ea8474c539d/ruff-0.14.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c8753dfa44ebb2cde10ce5b4d2ef55a41fb9d9b16732a2c5df64620dbda44a3", size = 11925177, upload-time = "2025-10-23T19:36:24.778Z" }, + { url = "https://files.pythonhosted.org/packages/15/8b/c44cf7fe6e59ab24a9d939493a11030b503bdc2a16622cede8b7b1df0114/ruff-0.14.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d0bbeffb8d9f4fccf7b5198d566d0bad99a9cb622f1fc3467af96cb8773c9e3", size = 12358285, upload-time = "2025-10-23T19:36:26.979Z" }, + { url = "https://files.pythonhosted.org/packages/45/01/47701b26254267ef40369aea3acb62a7b23e921c27372d127e0f3af48092/ruff-0.14.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7047f0c5a713a401e43a88d36843d9c83a19c584e63d664474675620aaa634a8", size = 12303832, upload-time = "2025-10-23T19:36:29.192Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5c/ae7244ca4fbdf2bee9d6405dcd5bc6ae51ee1df66eb7a9884b77b8af856d/ruff-0.14.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bf8d2f9aa1602599217d82e8e0af7fd33e5878c4d98f37906b7c93f46f9a839", size = 13036995, upload-time = "2025-10-23T19:36:31.861Z" }, + { url = "https://files.pythonhosted.org/packages/27/4c/0860a79ce6fd4c709ac01173f76f929d53f59748d0dcdd662519835dae43/ruff-0.14.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1c505b389e19c57a317cf4b42db824e2fca96ffb3d86766c1c9f8b96d32048a7", size = 14512649, upload-time = "2025-10-23T19:36:33.915Z" }, + { url = "https://files.pythonhosted.org/packages/7f/7f/d365de998069720a3abfc250ddd876fc4b81a403a766c74ff9bde15b5378/ruff-0.14.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a307fc45ebd887b3f26b36d9326bb70bf69b01561950cdcc6c0bdf7bb8e0f7cc", size = 14088182, upload-time = "2025-10-23T19:36:36.983Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ea/d8e3e6b209162000a7be1faa41b0a0c16a133010311edc3329753cc6596a/ruff-0.14.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61ae91a32c853172f832c2f40bd05fd69f491db7289fb85a9b941ebdd549781a", size = 13599516, upload-time = "2025-10-23T19:36:39.208Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ea/c7810322086db68989fb20a8d5221dd3b79e49e396b01badca07b433ab45/ruff-0.14.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1967e40286f63ee23c615e8e7e98098dedc7301568bd88991f6e544d8ae096", size = 13272690, upload-time = "2025-10-23T19:36:41.453Z" }, + { url = "https://files.pythonhosted.org/packages/a9/39/10b05acf8c45786ef501d454e00937e1b97964f846bf28883d1f9619928a/ruff-0.14.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2877f02119cdebf52a632d743a2e302dea422bfae152ebe2f193d3285a3a65df", size = 13496497, upload-time = "2025-10-23T19:36:43.61Z" }, + { url = "https://files.pythonhosted.org/packages/59/a1/1f25f8301e13751c30895092485fada29076e5e14264bdacc37202e85d24/ruff-0.14.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e681c5bc777de5af898decdcb6ba3321d0d466f4cb43c3e7cc2c3b4e7b843a05", size = 12266116, upload-time = "2025-10-23T19:36:45.625Z" }, + { url = "https://files.pythonhosted.org/packages/5c/fa/0029bfc9ce16ae78164e6923ef392e5f173b793b26cc39aa1d8b366cf9dc/ruff-0.14.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e21be42d72e224736f0c992cdb9959a2fa53c7e943b97ef5d081e13170e3ffc5", size = 12281345, upload-time = "2025-10-23T19:36:47.618Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ab/ece7baa3c0f29b7683be868c024f0838770c16607bea6852e46b202f1ff6/ruff-0.14.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b8264016f6f209fac16262882dbebf3f8be1629777cf0f37e7aff071b3e9b92e", size = 12629296, upload-time = "2025-10-23T19:36:49.789Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7f/638f54b43f3d4e48c6a68062794e5b367ddac778051806b9e235dfb7aa81/ruff-0.14.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5ca36b4cb4db3067a3b24444463ceea5565ea78b95fe9a07ca7cb7fd16948770", size = 13371610, upload-time = "2025-10-23T19:36:51.882Z" }, + { url = "https://files.pythonhosted.org/packages/8d/35/3654a973ebe5b32e1fd4a08ed2d46755af7267da7ac710d97420d7b8657d/ruff-0.14.2-py3-none-win32.whl", hash = "sha256:41775927d287685e08f48d8eb3f765625ab0b7042cc9377e20e64f4eb0056ee9", size = 12415318, upload-time = "2025-10-23T19:36:53.961Z" }, + { url = "https://files.pythonhosted.org/packages/71/30/3758bcf9e0b6a4193a6f51abf84254aba00887dfa8c20aba18aa366c5f57/ruff-0.14.2-py3-none-win_amd64.whl", hash = "sha256:0df3424aa5c3c08b34ed8ce099df1021e3adaca6e90229273496b839e5a7e1af", size = 13565279, upload-time = "2025-10-23T19:36:56.578Z" }, + { url = "https://files.pythonhosted.org/packages/2e/5d/aa883766f8ef9ffbe6aa24f7192fb71632f31a30e77eb39aa2b0dc4290ac/ruff-0.14.2-py3-none-win_arm64.whl", hash = "sha256:ea9d635e83ba21569fbacda7e78afbfeb94911c9434aff06192d9bc23fd5495a", size = 12554956, upload-time = "2025-10-23T19:36:58.714Z" }, +] From 05d44b2eec469ad3b5a1ca40d5526b67fb29bd2d Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:13:36 +0000 Subject: [PATCH 10/30] file-org-workflows: Templatize GitHub Actions workflows --- .github/actions/tests.yml | 39 +++++++++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 35 ++++------------------------------- 2 files changed, 43 insertions(+), 31 deletions(-) create mode 100644 .github/actions/tests.yml diff --git a/.github/actions/tests.yml b/.github/actions/tests.yml new file mode 100644 index 0000000..b287577 --- /dev/null +++ b/.github/actions/tests.yml @@ -0,0 +1,39 @@ +name: Reusable Python CI + +on: + workflow_call: + inputs: + project-path: + required: true + type: string + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.13' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r ${{ inputs.project-path }}/requirements.txt + pip install ruff black mypy pytest + + - name: Lint with ruff + continue-on-error: true + run: ruff check ${{ inputs.project-path }}/src ${{ inputs.project-path }}/tests + + - name: Format with black + run: black --check ${{ inputs.project-path }}/src ${{ inputs.project-path }}/tests + + - name: Typecheck with mypy + run: mypy ${{ inputs.project-path }}/src + + - name: Test with pytest + run: pytest ${{ inputs.project-path }}/tests diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 248fcbe..be9345c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,3 @@ - name: Python CI on: @@ -8,33 +7,7 @@ on: branches: [ "**" ] jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.13' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r Beginner/file_organiser/requirements.txt - pip install ruff black mypy - - - name: Lint with ruff - continue-on-error: true - run: ruff check Beginner/file_organiser/src Beginner/file_organiser/tests - - - name: Format with black - run: black --check Beginner/file_organiser/src Beginner/file_organiser/tests - - - name: Typecheck with mypy - run: mypy Beginner/file_organiser/src - - - name: Test with pytest - run: pytest Beginner/file_organiser/tests + file_organiser: + uses: ./.github/actions/tests.yml + with: + project-path: Beginner/file_organiser From e8f44908712a129fe4a98a9f2ad0479946228717 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:16:09 +0000 Subject: [PATCH 11/30] file-org-workflows: add uses tag --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be9345c..369568c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,6 @@ on: jobs: file_organiser: - uses: ./.github/actions/tests.yml + uses: ./.github/actions/tests.yml@file-org-workflows with: project-path: Beginner/file_organiser From daa324fb40d8db0dd2857f6d9ebb71549f725f4f Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:19:36 +0000 Subject: [PATCH 12/30] file-org-workflows: move action --- .github/workflows/ci.yml | 2 +- .github/{actions => workflows}/tests.yml | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename .github/{actions => workflows}/tests.yml (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 369568c..512e102 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,6 @@ on: jobs: file_organiser: - uses: ./.github/actions/tests.yml@file-org-workflows + uses: ./.github/workflows/tests.yml@file-org-workflows with: project-path: Beginner/file_organiser diff --git a/.github/actions/tests.yml b/.github/workflows/tests.yml similarity index 100% rename from .github/actions/tests.yml rename to .github/workflows/tests.yml From 5c29a81bb16a9e8f901a24de51051a6bb766bf76 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:20:18 +0000 Subject: [PATCH 13/30] file-org-workflows: "cannot specify version when calling local workflows" --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 512e102..8770018 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,6 @@ on: jobs: file_organiser: - uses: ./.github/workflows/tests.yml@file-org-workflows + uses: ./.github/workflows/tests.yml with: project-path: Beginner/file_organiser From 08d73232e1de1823de6ad65b475caea824749546 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:26:11 +0000 Subject: [PATCH 14/30] file-org-workflows: move actions and only trigger tests on !main --- .github/workflows/{ => actions}/tests.yml | 0 .github/workflows/ci.yml | 13 ------------- .github/workflows/file-organiser-test.yml | 14 ++++++++++++++ 3 files changed, 14 insertions(+), 13 deletions(-) rename .github/workflows/{ => actions}/tests.yml (100%) delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/file-organiser-test.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/actions/tests.yml similarity index 100% rename from .github/workflows/tests.yml rename to .github/workflows/actions/tests.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 8770018..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Python CI - -on: - push: - branches: [ "**" ] - pull_request: - branches: [ "**" ] - -jobs: - file_organiser: - uses: ./.github/workflows/tests.yml - with: - project-path: Beginner/file_organiser diff --git a/.github/workflows/file-organiser-test.yml b/.github/workflows/file-organiser-test.yml new file mode 100644 index 0000000..65687cb --- /dev/null +++ b/.github/workflows/file-organiser-test.yml @@ -0,0 +1,14 @@ +name: file-organiser-test + +on: + push: + branches-ignore: + - main + #pull_request: + # branches: [ "**" ] + +jobs: + file_organiser: + uses: ./.github/workflows/actions/tests.yml + with: + project-path: Beginner/file_organiser From 332523c1d5dc5a52551a52f2225bcda606b0c521 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:27:19 +0000 Subject: [PATCH 15/30] file-org-workflows: workflows has to be at top level --- .github/workflows/file-organiser-test.yml | 2 +- .github/workflows/{actions => }/tests.yml | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{actions => }/tests.yml (100%) diff --git a/.github/workflows/file-organiser-test.yml b/.github/workflows/file-organiser-test.yml index 65687cb..816b6ad 100644 --- a/.github/workflows/file-organiser-test.yml +++ b/.github/workflows/file-organiser-test.yml @@ -9,6 +9,6 @@ on: jobs: file_organiser: - uses: ./.github/workflows/actions/tests.yml + uses: ./.github/workflows/tests.yml with: project-path: Beginner/file_organiser diff --git a/.github/workflows/actions/tests.yml b/.github/workflows/tests.yml similarity index 100% rename from .github/workflows/actions/tests.yml rename to .github/workflows/tests.yml From 1f5b7ee6b592b22eb5061b61153accb6f1a93b21 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:36:28 +0000 Subject: [PATCH 16/30] file-org-workflows: code coverage summary --- .github/workflows/tests.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b287577..ac572ec 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -r ${{ inputs.project-path }}/requirements.txt - pip install ruff black mypy pytest + pip install ruff black mypy pytest pytest-cov - name: Lint with ruff continue-on-error: true @@ -35,5 +35,13 @@ jobs: - name: Typecheck with mypy run: mypy ${{ inputs.project-path }}/src - - name: Test with pytest - run: pytest ${{ inputs.project-path }}/tests + - name: Test with pytest and generate coverage summary + run: | + pytest --cov=${{ inputs.project-path }}/src --cov-report=term-missing ${{ inputs.project-path }}/tests > coverage_summary.md + + - name: Display coverage summary in job summary + run: | + echo '## Code Coverage Summary' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + cat coverage_summary.md >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY From 3c63b771f03c7ba36f5b5976eabc8dbc5fc6ad49 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:41:26 +0000 Subject: [PATCH 17/30] file-org-workflows: summary --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ac572ec..9508446 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,7 +41,8 @@ jobs: - name: Display coverage summary in job summary run: | - echo '## Code Coverage Summary' >> $GITHUB_STEP_SUMMARY + echo "## Code Coverage Summary for $(${{ inputs.project-path }} | cut -d '/' -f 2)" >> $GITHUB_STEP_SUMMARY + echoinputs.project-path })" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY cat coverage_summary.md >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY From 52b8a016447b5eb2184f7805c4a89b8e489dfa58 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:42:57 +0000 Subject: [PATCH 18/30] file-org-workflows: summary --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9508446..e5b7b27 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,7 +41,7 @@ jobs: - name: Display coverage summary in job summary run: | - echo "## Code Coverage Summary for $(${{ inputs.project-path }} | cut -d '/' -f 2)" >> $GITHUB_STEP_SUMMARY + echo "## Code Coverage Summary for $(echo ${{ inputs.project-path }} | cut -d '/' -f 2)" >> $GITHUB_STEP_SUMMARY echoinputs.project-path })" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY cat coverage_summary.md >> $GITHUB_STEP_SUMMARY From 33c801645e4ecd46bc8b4d64fd9f68a9bc97eb07 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:50:27 +0000 Subject: [PATCH 19/30] file-org-workflows: silly ai prompting --- .github/workflows/tests.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e5b7b27..b2d20e1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -42,7 +42,6 @@ jobs: - name: Display coverage summary in job summary run: | echo "## Code Coverage Summary for $(echo ${{ inputs.project-path }} | cut -d '/' -f 2)" >> $GITHUB_STEP_SUMMARY - echoinputs.project-path })" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY cat coverage_summary.md >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY From 2f1c6f9fdee68d281820b3c4a24391af107d8d05 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:51:27 +0000 Subject: [PATCH 20/30] file-org-workflows: code block --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b2d20e1..345a82b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -42,6 +42,6 @@ jobs: - name: Display coverage summary in job summary run: | echo "## Code Coverage Summary for $(echo ${{ inputs.project-path }} | cut -d '/' -f 2)" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY cat coverage_summary.md >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY From 1272871f81b5b43fd5d351583f86f49375b32dc7 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 07:51:27 +0000 Subject: [PATCH 21/30] file-org-workflows: move to a action --- .../python-test/action.yml} | 30 +++++++++---------- .github/workflows/file-organiser-test.yml | 11 +++---- 2 files changed, 20 insertions(+), 21 deletions(-) rename .github/{workflows/tests.yml => actions/python-test/action.yml} (77%) diff --git a/.github/workflows/tests.yml b/.github/actions/python-test/action.yml similarity index 77% rename from .github/workflows/tests.yml rename to .github/actions/python-test/action.yml index 345a82b..2ec7493 100644 --- a/.github/workflows/tests.yml +++ b/.github/actions/python-test/action.yml @@ -1,19 +1,12 @@ -name: Reusable Python CI - -on: - workflow_call: - inputs: - project-path: - required: true - type: string - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - +name: 'Python Test Action' +description: 'A custom action to run tests, lint, format, and typecheck a Python project.' +inputs: + project-path: + description: 'The path to the Python project.' + required: true +runs: + using: "composite" + steps: - name: Set up Python uses: actions/setup-python@v4 with: @@ -24,20 +17,25 @@ jobs: python -m pip install --upgrade pip pip install -r ${{ inputs.project-path }}/requirements.txt pip install ruff black mypy pytest pytest-cov + shell: bash - name: Lint with ruff continue-on-error: true run: ruff check ${{ inputs.project-path }}/src ${{ inputs.project-path }}/tests + shell: bash - name: Format with black run: black --check ${{ inputs.project-path }}/src ${{ inputs.project-path }}/tests + shell: bash - name: Typecheck with mypy run: mypy ${{ inputs.project-path }}/src + shell: bash - name: Test with pytest and generate coverage summary run: | pytest --cov=${{ inputs.project-path }}/src --cov-report=term-missing ${{ inputs.project-path }}/tests > coverage_summary.md + shell: bash - name: Display coverage summary in job summary run: | diff --git a/.github/workflows/file-organiser-test.yml b/.github/workflows/file-organiser-test.yml index 816b6ad..91a2888 100644 --- a/.github/workflows/file-organiser-test.yml +++ b/.github/workflows/file-organiser-test.yml @@ -4,11 +4,12 @@ on: push: branches-ignore: - main - #pull_request: - # branches: [ "**" ] jobs: file_organiser: - uses: ./.github/workflows/tests.yml - with: - project-path: Beginner/file_organiser + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/python-test + with: + project-path: Beginner/file_organiser From ec9c4fb58429a2fc1598c045047d224b10f971fc Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 08:27:03 +0000 Subject: [PATCH 22/30] file-org-workflows: add shell --- .github/actions/python-test/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/python-test/action.yml b/.github/actions/python-test/action.yml index 2ec7493..700d46d 100644 --- a/.github/actions/python-test/action.yml +++ b/.github/actions/python-test/action.yml @@ -11,6 +11,7 @@ runs: uses: actions/setup-python@v4 with: python-version: '3.13' + shell: bash - name: Install dependencies run: | @@ -38,6 +39,7 @@ runs: shell: bash - name: Display coverage summary in job summary + shell: bash run: | echo "## Code Coverage Summary for $(echo ${{ inputs.project-path }} | cut -d '/' -f 2)" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY From a4cfb639f3b59eeb375e492607c8c7a874bd3727 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 08:27:57 +0000 Subject: [PATCH 23/30] file-org-workflows: remove shell --- .github/actions/python-test/action.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/python-test/action.yml b/.github/actions/python-test/action.yml index 700d46d..85ff0fe 100644 --- a/.github/actions/python-test/action.yml +++ b/.github/actions/python-test/action.yml @@ -11,7 +11,6 @@ runs: uses: actions/setup-python@v4 with: python-version: '3.13' - shell: bash - name: Install dependencies run: | From c7a9a5d03a1f82d8ecf8f6fa8a1bf77cf5941832 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 08:32:20 +0000 Subject: [PATCH 24/30] file-org-workflows: add file-org path --- .github/workflows/file-organiser-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/file-organiser-test.yml b/.github/workflows/file-organiser-test.yml index 91a2888..e6ae0d0 100644 --- a/.github/workflows/file-organiser-test.yml +++ b/.github/workflows/file-organiser-test.yml @@ -4,6 +4,8 @@ on: push: branches-ignore: - main + paths: + - "Beginner/file_organiser/**" jobs: file_organiser: From fb14ba28b93a9760afe893b0e5a0c9ebf9e1710b Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 08:49:57 +0000 Subject: [PATCH 25/30] file-org-workflows: change logic of recursive --- Beginner/file_organiser/src/file_organiser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Beginner/file_organiser/src/file_organiser.py b/Beginner/file_organiser/src/file_organiser.py index 33756c5..c62e208 100644 --- a/Beginner/file_organiser/src/file_organiser.py +++ b/Beginner/file_organiser/src/file_organiser.py @@ -15,7 +15,7 @@ def get_type(file_path: Path | str) -> str: # Using a path, return all files, using full Path and filename from Path.Walk() -def get_files(path: Path | str, recursive=False): +def get_files(path: Path | str, recursive=True): p = Path(path) if not p.exists(): # If the path doesn't exist, throw a error @@ -28,12 +28,12 @@ def get_files(path: Path | str, recursive=False): for dirpath, subdirs, files in p.walk(): for f in files: yield dirpath / f - if recursive: + if not recursive: break # This fuction calls the above 2 fuctions, to grab a list of files, and then fetching the file types, saving within a Counter -def process_files(path: Path | str, recursive=False): +def process_files(path: Path | str, recursive=True): counts: Counter[str] = Counter() for f in track(get_files(path, recursive), description="Working...."): try: From df6c22ae81b8fd7fb4fd8f335e2bbb327c44cfd9 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 08:53:52 +0000 Subject: [PATCH 26/30] file-org-workflows: set no recurive arg to false --- Beginner/file_organiser/src/file_organiser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Beginner/file_organiser/src/file_organiser.py b/Beginner/file_organiser/src/file_organiser.py index c62e208..d2aa796 100644 --- a/Beginner/file_organiser/src/file_organiser.py +++ b/Beginner/file_organiser/src/file_organiser.py @@ -60,7 +60,7 @@ def parse_args(argv=None): ap.add_argument( "-n", "--no-recursive", - action="store_true", + action="store_false", help="Disable recursion if you add non-recursive mode", ) ap.add_argument("--list", action="store_true", help="(future) list files with detected MIME") From c681b0abf5951e0f3380f176551f9cd086fea666 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 08:54:02 +0000 Subject: [PATCH 27/30] file-org-workflows: additional test and fixes --- .../tests/unit/test_file_organiser.py | 72 +++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/Beginner/file_organiser/tests/unit/test_file_organiser.py b/Beginner/file_organiser/tests/unit/test_file_organiser.py index 4dcc82b..d91b598 100644 --- a/Beginner/file_organiser/tests/unit/test_file_organiser.py +++ b/Beginner/file_organiser/tests/unit/test_file_organiser.py @@ -1,33 +1,42 @@ #!/usr/bin/env python3 import pytest +from collections import Counter from file_organiser import get_files, get_type, main, process_files -# Test main with args +# Test main def test_path(tmp_path): + """Test main with a directory containing one file, expecting 1 file to be processed.""" (tmp_path / "file1.txt").touch() amount = main([str(tmp_path)]) - assert amount > 0 + assert amount == 1 -def test_no_path(): - amount = main([]) - assert amount > 0 +def test_main_empty_dir(tmp_path): + """Test main with an empty directory, should process 0 files.""" + amount = main([str(tmp_path)]) + assert amount == 0 -def test_no_path_recursive(): - amount = main(["--no-recursive"]) - assert amount > 0 +def test_main_no_path(tmp_path, monkeypatch): + """Test main with no path, which should default to the current directory.""" + monkeypatch.chdir(tmp_path) + (tmp_path / "file1.txt").touch() + amount = main([]) + assert amount == 1 -def test_file_not_found(tmp_path): - with pytest.raises(FileNotFoundError, match="does not exist"): - list(get_files(tmp_path / "not-here")) + +def test_main_file_not_found(): + """Test main with a non-existent file path.""" + with pytest.raises(FileNotFoundError): + main(["/non/existent/path"]) def test_not_dir(tmp_path): + """Test main with a non-directory path.""" file = tmp_path / "text.txt" file.touch() with pytest.raises(NotADirectoryError, match="is not a directory"): @@ -35,6 +44,7 @@ def test_not_dir(tmp_path): def test_with_file(tmp_path): + """Test main with a file path.""" fake_jpeg = tmp_path / "test.jpg" fake_jpeg.write_bytes(b"\xff\xd8\xff\xe0") file_type = main(["--file", str(fake_jpeg)]) @@ -42,7 +52,14 @@ def test_with_file(tmp_path): # Test get_files +def test_file_not_found(tmp_path): + """Test get_files with a non-existent file path.""" + with pytest.raises(FileNotFoundError, match="does not exist"): + list(get_files(tmp_path / "not-here")) + + def test_get_files_recursive(tmp_path): + """Test get_files with recursive mode enabled.""" # Create a dummy directory structure (tmp_path / "subdir1").mkdir() (tmp_path / "subdir2").mkdir() @@ -59,7 +76,7 @@ def test_get_files_recursive(tmp_path): def test_get_files_non_recursive(tmp_path): - # Create a dummy directory structure + """Test get_files with non-recursive mode enabled.""" (tmp_path / "subdir1").mkdir() (tmp_path / "subdir2").mkdir() (tmp_path / "file1.txt").touch() @@ -67,12 +84,20 @@ def test_get_files_non_recursive(tmp_path): (tmp_path / "subdir2" / "file3.pdf").touch() # Test non-recursive behavior - files = list(get_files(tmp_path, recursive=True)) + files = list(get_files(tmp_path, recursive=False)) assert len(files) == 1 assert tmp_path / "file1.txt" in files +def test_get_files_empty_dir(tmp_path): + """Test get_files with an empty directory.""" + files = list(get_files(tmp_path)) + assert len(files) == 0 + + +# Test process_files def test_process_files_recursive(tmp_path): + """Test process_files with recursive mode enabled.""" # Create dummy files with different types (tmp_path / "file1.txt").write_text("hello") (tmp_path / "file2.jpg").touch() # python-magic will likely identify this as empty data @@ -84,8 +109,20 @@ def test_process_files_recursive(tmp_path): assert counts["text/plain"] == 1 +def test_process_files_non_recursive(tmp_path): + """Test process_files with non-recursive mode enabled.""" + # Create dummy files + (tmp_path / "file1.txt").write_text("hello") + (tmp_path / "subdir").mkdir() + (tmp_path / "subdir" / "file2.txt").write_text("world") + + counts = process_files(tmp_path, recursive=False) + assert counts == Counter({"text/plain": 1}) + + # Test get_type def test_get_type_image(tmp_path): + """Test get_type with an image file.""" fake_jpeg = tmp_path / "test.jpg" fake_jpeg.write_bytes(b"\xff\xd8\xff\xe0") type = get_type(str(fake_jpeg)) @@ -93,6 +130,7 @@ def test_get_type_image(tmp_path): def test_get_type_with_temp_file(tmp_path): + """Test get_type with a temporary file.""" # Create a dummy txt file txt_content = b"This is a dummy text file." txt_file = tmp_path / "dummy.txt" @@ -101,3 +139,11 @@ def test_get_type_with_temp_file(tmp_path): # test with get_type type = get_type(txt_file) assert type == "text/plain" + + +def test_get_type_empty_file(tmp_path): + """Test get_type with an empty file.""" + empty_file = tmp_path / "empty.dat" + empty_file.touch() + file_type = get_type(empty_file) + assert file_type == "inode/x-empty" From 335edf9247f0316e2751b9bfca37e98ef8616faf Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 08:58:25 +0000 Subject: [PATCH 28/30] file-org-workflows: ruff fixes --- Beginner/file_organiser/tests/unit/test_file_organiser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Beginner/file_organiser/tests/unit/test_file_organiser.py b/Beginner/file_organiser/tests/unit/test_file_organiser.py index d91b598..3963d5c 100644 --- a/Beginner/file_organiser/tests/unit/test_file_organiser.py +++ b/Beginner/file_organiser/tests/unit/test_file_organiser.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -import pytest from collections import Counter +import pytest + from file_organiser import get_files, get_type, main, process_files From 1c073772f921a2955988d77a4eba63eb9e83dc14 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 09:04:31 +0000 Subject: [PATCH 29/30] file-org-workflows: increase code coverage --- .../tests/unit/test_file_organiser.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Beginner/file_organiser/tests/unit/test_file_organiser.py b/Beginner/file_organiser/tests/unit/test_file_organiser.py index 3963d5c..7872290 100644 --- a/Beginner/file_organiser/tests/unit/test_file_organiser.py +++ b/Beginner/file_organiser/tests/unit/test_file_organiser.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 +import subprocess from collections import Counter +from pathlib import Path import pytest @@ -121,6 +123,19 @@ def test_process_files_non_recursive(tmp_path): assert counts == Counter({"text/plain": 1}) +def test_process_files_exception(tmp_path, monkeypatch): + """Test process_files with an exception during file type retrieval.""" + (tmp_path / "file1.txt").touch() + + def mock_get_type(path): + raise Exception("Test exception") + + monkeypatch.setattr("file_organiser.get_type", mock_get_type) + + counts = process_files(tmp_path) + assert counts.total() == 0 + + # Test get_type def test_get_type_image(tmp_path): """Test get_type with an image file.""" @@ -148,3 +163,19 @@ def test_get_type_empty_file(tmp_path): empty_file.touch() file_type = get_type(empty_file) assert file_type == "inode/x-empty" + + +def test_main_as_script(tmp_path): + """Test running the script as the main program.""" + (tmp_path / "file1.txt").touch() + + # Get the path to the Beginner/file_organiser directory + file_organiser_dir = Path(__file__).parent.parent.parent + + result = subprocess.run( + ["python", "src/file_organiser.py", str(tmp_path)], + capture_output=True, + text=True, + cwd=str(file_organiser_dir), + ) + assert result.returncode == 1 From beef094827fd820922d6df0a5dae5d79e4990e99 Mon Sep 17 00:00:00 2001 From: Adam Charlton Date: Thu, 30 Oct 2025 09:09:53 +0000 Subject: [PATCH 30/30] file-org-workflows: coverage --- .github/actions/python-test/action.yml | 21 +++++++++++++------ Beginner/file_organiser/.coveragerc | 6 ++++++ .../tests/unit/test_file_organiser.py | 2 +- 3 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 Beginner/file_organiser/.coveragerc diff --git a/.github/actions/python-test/action.yml b/.github/actions/python-test/action.yml index 85ff0fe..56f23d2 100644 --- a/.github/actions/python-test/action.yml +++ b/.github/actions/python-test/action.yml @@ -16,7 +16,7 @@ runs: run: | python -m pip install --upgrade pip pip install -r ${{ inputs.project-path }}/requirements.txt - pip install ruff black mypy pytest pytest-cov + pip install ruff black mypy pytest pytest-cov coverage shell: bash - name: Lint with ruff @@ -32,15 +32,24 @@ runs: run: mypy ${{ inputs.project-path }}/src shell: bash - - name: Test with pytest and generate coverage summary - run: | - pytest --cov=${{ inputs.project-path }}/src --cov-report=term-missing ${{ inputs.project-path }}/tests > coverage_summary.md + - name: Test with pytest + run: pytest --cov=${{ inputs.project-path }}/src ${{ inputs.project-path }}/tests shell: bash - - name: Display coverage summary in job summary + - name: Combine coverage reports + run: coverage combine + shell: bash + working-directory: ${{ inputs.project-path }} + + - name: Generate coverage summary + run: coverage report --show-missing > coverage_summary.md shell: bash + working-directory: ${{ inputs.project-path }} + + - name: Display coverage summary in job summary run: | echo "## Code Coverage Summary for $(echo ${{ inputs.project-path }} | cut -d '/' -f 2)" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY - cat coverage_summary.md >> $GITHUB_STEP_SUMMARY + cat ${{ inputs.project-path }}/coverage_summary.md >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY + shell: bash diff --git a/Beginner/file_organiser/.coveragerc b/Beginner/file_organiser/.coveragerc new file mode 100644 index 0000000..32ab02a --- /dev/null +++ b/Beginner/file_organiser/.coveragerc @@ -0,0 +1,6 @@ +[run] +source = src +parallel = true + +[report] +show_missing = true diff --git a/Beginner/file_organiser/tests/unit/test_file_organiser.py b/Beginner/file_organiser/tests/unit/test_file_organiser.py index 7872290..91355ec 100644 --- a/Beginner/file_organiser/tests/unit/test_file_organiser.py +++ b/Beginner/file_organiser/tests/unit/test_file_organiser.py @@ -173,7 +173,7 @@ def test_main_as_script(tmp_path): file_organiser_dir = Path(__file__).parent.parent.parent result = subprocess.run( - ["python", "src/file_organiser.py", str(tmp_path)], + ["coverage", "run", "--append", "src/file_organiser.py", str(tmp_path)], capture_output=True, text=True, cwd=str(file_organiser_dir),