Skip to content

Commit 2165758

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

22 files changed

Lines changed: 1425 additions & 474 deletions

.flake8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[flake8]
2+
max-line-length = 130

.github/workflows/cd.yml

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

.github/workflows/ci.yml

Lines changed: 79 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,56 @@ 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 mypy types-PyYAML
40+
41+
- name: Run Linters and Formatters Check
42+
run: |
43+
flake8 src tests
44+
black --check src tests
45+
46+
- name: Run Type Checker (Mypy)
47+
run: |
48+
# Mypy может требовать установленных зависимостей для корректной проверки
49+
mypy src tests
50+
51+
# --- Задание для тестов на CPython ---
1152
test:
53+
needs: lint-type-check # Запускаем тесты ПОСЛЕ проверки качества кода
1254
strategy:
55+
fail-fast: false # Не отменять другие тесты при падении одного
1356
matrix:
14-
os: [ ubuntu-latest, ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest ]
15-
python-version: [ 3.9, '3.10', '3.11' ]
57+
os: [ ubuntu-20.04, ubuntu-22.04, ubuntu-24.04, macos-latest, windows-latest ]
58+
python-version: [ 3.9, '3.10', '3.11', '3.12' ]
1659

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

1963
steps:
2064
- name: Checkout Code
@@ -29,33 +73,46 @@ jobs:
2973
uses: actions/cache@v3
3074
with:
3175
path: ~/.cache/pip
32-
key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.cfg') }}
76+
# Ключ кэша включает ОС, версию Python и хэш setup.cfg
77+
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/setup.cfg') }}
3378
restore-keys: |
79+
${{ runner.os }}-pip-${{ matrix.python-version }}-
3480
${{ runner.os }}-pip-
3581
3682
- name: Install Dependencies
3783
run: |
3884
python -m pip install --upgrade pip
39-
pip install -r requirements.txt
40-
pip install -e .
85+
# Устанавливаем пакет и dev-зависимости из setup.cfg
86+
pip install -e .[dev]
4187
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
88+
# --- Шаги сборки PyInstaller и build УДАЛЕНЫ ---
4989

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

107+
# --- Задание для тестов на PyPy ---
54108
test-pypy:
109+
needs: lint-type-check # Запускаем тесты ПОСЛЕ проверки качества кода
55110
runs-on: ubuntu-latest
56111
strategy:
112+
fail-fast: false
57113
matrix:
58-
python-version: [ pypy-3.9 ]
114+
# Добавлена версия PyPy 3.10 (проверьте доступность в actions/setup-python)
115+
python-version: [ pypy-3.9, pypy-3.10 ]
59116

60117
steps:
61118
- name: Checkout Code
@@ -70,21 +127,19 @@ jobs:
70127
uses: actions/cache@v3
71128
with:
72129
path: ~/.cache/pip
73-
key: pypy-pip-${{ hashFiles('**/setup.cfg') }}
130+
key: pypy-${{ matrix.python-version }}-pip-${{ hashFiles('**/setup.cfg') }}
74131
restore-keys: |
75-
pypy-pip-
132+
pypy-${{ matrix.python-version }}-pip-
76133
77134
- name: Install Dependencies
78135
run: |
79136
python -m pip install --upgrade pip
80-
pip install -r requirements.txt
81-
pip install -e .
82-
pip install build pytest
137+
# Устанавливаем с dev зависимостями из setup.cfg
138+
pip install -e .[dev]
139+
# build и pytest теперь должны быть в [dev]
83140
84-
- name: Build with python -m build
85-
run: |
86-
python -m build
141+
# --- Шаг сборки build УДАЛЕН ---
87142

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

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[build-system]
22
requires = ["setuptools>=45", "wheel"]
3-
build-backend = "setuptools.build_meta"
3+
build-backend = "setuptools.build_meta"
4+
5+
[tool.black]
6+
line-length = 130

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>=25.1.0
40+
mypy>=1.0
41+
types-PyYAML
42+
pyyaml
43+
pathspec
44+
autoflake

src/treemapper/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
from .treemapper import main
2-
from .version import __version__

src/treemapper/cli.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,61 @@
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
56

67

7-
def parse_args() -> Tuple[Path, Path, Path, bool, int]:
8+
# ---> ИЗМЕНЕНИЕ: Возвращаем Path для output_file, т.к. он всегда Path <---
9+
def parse_args() -> Tuple[Path, Optional[Path], Path, bool, int]:
810
"""Parse command line arguments."""
911
parser = argparse.ArgumentParser(
12+
prog="treemapper",
1013
description="Generate a YAML representation of a directory structure.",
11-
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
14+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
15+
)
1216

13-
parser.add_argument(
14-
"directory",
15-
nargs="?",
16-
default=".",
17-
help="The directory to analyze")
17+
parser.add_argument("directory", nargs="?", default=".", help="The directory to analyze")
1818

19-
parser.add_argument(
20-
"-i", "--ignore-file",
21-
default=None,
22-
help="Path to the custom ignore file (optional)")
19+
parser.add_argument("-i", "--ignore-file", default=None, help="Path to the custom ignore file (optional)")
2320

24-
parser.add_argument(
25-
"-o", "--output-file",
26-
default="./directory_tree.yaml",
27-
help="Path to the output YAML file")
21+
parser.add_argument("-o", "--output-file", default="./directory_tree.yaml", help="Path to the output YAML file")
2822

2923
parser.add_argument(
30-
"--no-default-ignores",
31-
action="store_true",
32-
help="Disable all default ignores (including .gitignore and .treemapperignore)")
24+
"--no-default-ignores", action="store_true", help="Disable default ignores (.treemapperignore, .gitignore, output file)"
25+
)
3326

3427
parser.add_argument(
35-
"-v", "--verbosity",
28+
"-v",
29+
"--verbosity",
3630
type=int,
3731
choices=range(0, 4),
3832
default=2,
3933
metavar="[0-3]",
40-
help="Set verbosity level (0: ERROR, 1: WARNING, 2: INFO, 3: DEBUG)")
34+
help="Set verbosity level (0: ERROR, 1: WARNING, 2: INFO, 3: DEBUG)",
35+
)
4136

4237
args = parser.parse_args()
4338

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.")
39+
try:
40+
root_dir = Path(args.directory).resolve(strict=True)
41+
if not root_dir.is_dir():
42+
print(f"Error: The path '{root_dir}' is not a valid directory.", file=sys.stderr)
43+
sys.exit(1)
44+
except FileNotFoundError:
45+
print(f"Error: The directory '{args.directory}' does not exist.", file=sys.stderr)
46+
sys.exit(1)
47+
except Exception as e:
48+
print(f"Error resolving directory path '{args.directory}': {e}", file=sys.stderr)
4749
sys.exit(1)
4850

4951
output_file = Path(args.output_file)
5052
if not output_file.is_absolute():
5153
output_file = Path.cwd() / output_file
5254

53-
ignore_file = Path(args.ignore_file) if args.ignore_file else None
55+
ignore_file_path: Optional[Path] = None
56+
if args.ignore_file:
57+
ignore_file_path = Path(args.ignore_file)
58+
if not ignore_file_path.is_absolute():
59+
ignore_file_path = Path.cwd() / ignore_file_path
5460

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

0 commit comments

Comments
 (0)