Skip to content

Commit 03ad6d1

Browse files
committed
adding more tests, refactoring
1 parent 12305a2 commit 03ad6d1

File tree

17 files changed

+1371
-437
lines changed

17 files changed

+1371
-437
lines changed

.github/workflows/cd.yml

Lines changed: 134 additions & 105 deletions
Large diffs are not rendered by default.

.github/workflows/ci.yml

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# .github/workflows/ci.yml
12
name: TreeMapper CI
23

34
on:
@@ -8,13 +9,57 @@ on:
89
- main
910

1011
jobs:
12+
# --- Задание для проверки качества кода ---
13+
lint-type-check:
14+
name: Lint & Type Check
15+
runs-on: ubuntu-latest # Достаточно одной ОС/версии Python
16+
steps:
17+
- name: Checkout Code
18+
uses: actions/checkout@v3
19+
20+
- name: Set up Python 3.11 # Используем одну из последних версий для проверок
21+
uses: actions/setup-python@v4
22+
with:
23+
python-version: '3.11'
24+
25+
- name: Cache pip Dependencies
26+
uses: actions/cache@v3
27+
with:
28+
# Используем setup.cfg для ключа кэша
29+
path: ~/.cache/pip
30+
key: ${{ runner.os }}-lint-pip-${{ hashFiles('**/setup.cfg') }}
31+
restore-keys: |
32+
${{ runner.os }}-lint-pip-
33+
34+
- name: Install Linters and Type Checker
35+
run: |
36+
python -m pip install --upgrade pip
37+
# Устанавливаем только dev-зависимости из setup.cfg
38+
pip install .[dev]
39+
# Если нужные пакеты не в [dev], добавьте: pip install flake8 black isort mypy types-PyYAML
40+
41+
- name: Run Linters and Formatters Check
42+
run: |
43+
flake8 src tests
44+
black --check src tests
45+
isort --check-only src tests
46+
47+
- name: Run Type Checker (Mypy)
48+
run: |
49+
# Mypy может требовать установленных зависимостей для корректной проверки
50+
mypy src tests
51+
52+
# --- Задание для тестов на CPython ---
1153
test:
54+
needs: lint-type-check # Запускаем тесты ПОСЛЕ проверки качества кода
1255
strategy:
56+
fail-fast: false # Не отменять другие тесты при падении одного
1357
matrix:
14-
os: [ ubuntu-latest, ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest ]
15-
python-version: [ 3.9, '3.10', '3.11' ]
58+
os: [ ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, macos-latest, windows-latest ]
59+
python-version: [ 3.9, '3.10', '3.11', '3.12' ]
1660

1761
runs-on: ${{ matrix.os }}
62+
# continue-on-error: ${{ matrix.experimental || false }} # Опционально для 3.13
1863

1964
steps:
2065
- name: Checkout Code
@@ -29,33 +74,46 @@ jobs:
2974
uses: actions/cache@v3
3075
with:
3176
path: ~/.cache/pip
32-
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.cfg') }}
77+
# Ключ кэша включает ОС, версию Python и хэш setup.cfg
78+
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/setup.cfg') }}
3379
restore-keys: |
80+
${{ runner.os }}-pip-${{ matrix.python-version }}-
3481
${{ runner.os }}-pip-
3582
3683
- name: Install Dependencies
3784
run: |
3885
python -m pip install --upgrade pip
39-
pip install -r requirements.txt
40-
pip install -e .
86+
# Устанавливаем пакет и dev-зависимости из setup.cfg
87+
pip install -e .[dev]
4188
42-
- name: Build with PyInstaller
43-
run: |
44-
python -m PyInstaller --clean -y --dist ./dist/${{ runner.os }} --workpath /tmp treemapper.spec
45-
46-
- name: Build with python -m build
47-
run: |
48-
python -m build
89+
# --- Шаги сборки PyInstaller и build УДАЛЕНЫ ---
4990

50-
- name: Run Tests
91+
- name: Run Tests with Coverage
5192
run: |
52-
pytest
93+
# Запускаем pytest с генерацией отчета покрытия в формате XML
94+
pytest -v --cov=src/treemapper --cov-report=xml
95+
96+
- name: Upload coverage reports to Codecov
97+
# Запускаем только для одной комбинации, чтобы не дублировать отчеты
98+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
99+
uses: codecov/codecov-action@v4
100+
# Не требует токена для публичных репозиториев на github.com
101+
# env:
102+
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # Для приватных репо
103+
with:
104+
files: ./coverage.xml # Файл отчета, созданный pytest-cov
105+
fail_ci_if_error: true
106+
verbose: true
53107

108+
# --- Задание для тестов на PyPy ---
54109
test-pypy:
110+
needs: lint-type-check # Запускаем тесты ПОСЛЕ проверки качества кода
55111
runs-on: ubuntu-latest
56112
strategy:
113+
fail-fast: false
57114
matrix:
58-
python-version: [ pypy-3.9 ]
115+
# Добавлена версия PyPy 3.10 (проверьте доступность в actions/setup-python)
116+
python-version: [ pypy-3.9, pypy-3.10 ]
59117

60118
steps:
61119
- name: Checkout Code
@@ -70,21 +128,19 @@ jobs:
70128
uses: actions/cache@v3
71129
with:
72130
path: ~/.cache/pip
73-
key: pypy-pip-${{ hashFiles('**/setup.cfg') }}
131+
key: pypy-${{ matrix.python-version }}-pip-${{ hashFiles('**/setup.cfg') }}
74132
restore-keys: |
75-
pypy-pip-
133+
pypy-${{ matrix.python-version }}-pip-
76134
77135
- name: Install Dependencies
78136
run: |
79137
python -m pip install --upgrade pip
80-
pip install -r requirements.txt
81-
pip install -e .
82-
pip install build pytest
138+
# Устанавливаем с dev зависимостями из setup.cfg
139+
pip install -e .[dev]
140+
# build и pytest теперь должны быть в [dev]
83141
84-
- name: Build with python -m build
85-
run: |
86-
python -m build
142+
# --- Шаг сборки build УДАЛЕН ---
87143

88144
- name: Run Tests
89145
run: |
90-
pytest
146+
pytest -v # Запускаем тесты без покрытия для PyPy, если оно не настроено

requirements.txt

Lines changed: 0 additions & 6 deletions
This file was deleted.

setup.cfg

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,27 @@ package_dir =
1818
packages = find:
1919
python_requires = >=3.9
2020
install_requires =
21-
pathspec
22-
pyyaml
21+
pathspec>=0.9
22+
pyyaml>=5.4
2323

2424
[options.packages.find]
2525
where = src
2626

2727
[options.entry_points]
2828
console_scripts =
29-
treemapper = treemapper.treemapper:main
29+
treemapper = treemapper.treemapper:main
30+
31+
[options.extras_require]
32+
dev =
33+
pytest>=7.0
34+
pytest-cov>=3.0
35+
build>=0.10
36+
twine>=4.0
37+
pyinstaller>=5.0
38+
flake8>=5.0
39+
black>=23.0
40+
isort>=5.10
41+
mypy>=1.0
42+
types-PyYAML
43+
pyyaml
44+
pathspec

src/treemapper/cli.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
# src/treemapper/cli.py
12
import argparse
23
import sys
34
from pathlib import Path
4-
from typing import Tuple
5+
from typing import Tuple, Optional # <--- Добавлен Optional
56

6-
7-
def parse_args() -> Tuple[Path, Path, Path, bool, int]:
7+
# ---> ИЗМЕНЕНИЕ: Заменяем | None на Optional[...] <---
8+
def parse_args() -> Tuple[Path, Optional[Path], Optional[Path], bool, int]:
89
"""Parse command line arguments."""
910
parser = argparse.ArgumentParser(
11+
prog='treemapper',
1012
description="Generate a YAML representation of a directory structure.",
1113
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
1214

@@ -29,7 +31,7 @@ def parse_args() -> Tuple[Path, Path, Path, bool, int]:
2931
parser.add_argument(
3032
"--no-default-ignores",
3133
action="store_true",
32-
help="Disable all default ignores (including .gitignore and .treemapperignore)")
34+
help="Disable default ignores (.treemapperignore, .gitignore, output file)")
3335

3436
parser.add_argument(
3537
"-v", "--verbosity",
@@ -41,15 +43,26 @@ def parse_args() -> Tuple[Path, Path, Path, bool, int]:
4143

4244
args = parser.parse_args()
4345

44-
root_dir = Path(args.directory).resolve()
45-
if not root_dir.is_dir():
46-
print(f"Error: The path '{root_dir}' is not a valid directory.")
47-
sys.exit(1)
46+
try:
47+
root_dir = Path(args.directory).resolve(strict=True)
48+
if not root_dir.is_dir():
49+
print(f"Error: The path '{root_dir}' is not a valid directory.", file=sys.stderr)
50+
sys.exit(1)
51+
except FileNotFoundError:
52+
print(f"Error: The directory '{args.directory}' does not exist.", file=sys.stderr)
53+
sys.exit(1)
54+
except Exception as e:
55+
print(f"Error resolving directory path '{args.directory}': {e}", file=sys.stderr)
56+
sys.exit(1)
4857

4958
output_file = Path(args.output_file)
5059
if not output_file.is_absolute():
5160
output_file = Path.cwd() / output_file
5261

53-
ignore_file = Path(args.ignore_file) if args.ignore_file else None
62+
ignore_file_path: Optional[Path] = None # Используем Optional для ясности
63+
if args.ignore_file:
64+
ignore_file_path = Path(args.ignore_file)
65+
if not ignore_file_path.is_absolute():
66+
ignore_file_path = Path.cwd() / ignore_file_path
5467

55-
return root_dir, ignore_file, output_file, args.no_default_ignores, args.verbosity
68+
return root_dir, ignore_file_path, output_file, args.no_default_ignores, args.verbosity

0 commit comments

Comments
 (0)