Organize documentation into topic folders (Claude, Python, Zscaler, Project template)

This commit is contained in:
2026-05-25 17:37:23 +02:00
parent 295a01aaa4
commit 46c4173440
22 changed files with 1203 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
# AI Agents - Project Rules
**Document Version:** v4 (independent, incremented on structural changes)
Rules and instructions for AI assistants (Claude Code, Cursor, Copilot, etc.)
## First-time setup
- **On first read of this file, immediately read all other `.md` files in the project root** (e.g. `PROJECT.md`, `CHANGELOG.md`, `DESIGN_DOCUMENT.md`) to get full project context before starting any task.
## Language
- **Always write all documentation in English**
## Dependency Management
- **Always use `poetry add`** to add dependencies, **never edit `pyproject.toml` directly**
```bash
poetry add requests
poetry add --group dev pytest
```
- Use `poetry remove` to remove dependencies — **never edit `pyproject.toml` manually**
## Project Structure
- Entry points are in the project root (named after project or by purpose: `project_name.py`, `cli.py`, `gui.py`, `server.py`)
- A project can have multiple entry points
- All modules belong in the `src/` folder
- Tests belong in the `tests/` folder
- Virtual environment is in `.venv/` (do not copy, do not generate)
## Code
- Always use type annotations
- Follow PEP8 and format with Ruff (88 characters per line)
- Before commit run `poetry run ruff check` and `poetry run mypy`
## Testing
- **Use pytest exclusively** - never use the `unittest` module
- No `unittest.TestCase` classes, no `self.assert*` methods
- Use plain `assert` statements and pytest fixtures
## Running
- Use `poetry run` to run scripts:
```bash
poetry run python project_name.py
poetry run pytest
```
## Logging
- Use **loguru** for logging - never use `print()` for debugging
- Never log secrets, passwords, tokens, or API keys
## Environment and Secrets
- Store secrets in `.env` file with `ENV_DEBUG=true/false` variable
- Load secrets using `python-dotenv` and `os.getenv()`
- **Never commit `.env` file**
## Git
- `.gitignore` should contain: `.venv/`, `__pycache__/`, `*.pyc`, `.mypy_cache/`, `.env`
- Do not commit `poetry.lock` only if it's a library (for applications, commit it)
- **Never commit this documentation** (`DESIGN_DOCUMENT.md`, `AGENTS.md`, `.claudeignore`)
- `PROJECT.md` **should be committed** - it's project-specific
## Versioning
- **Always ask user before bumping version** - never increase version automatically
- **Keep `CHANGELOG.md` updated** - document all significant changes as they are made
- Update `CHANGELOG.md` with changes before version bump
- Version is defined in `pyproject.toml` under `[project]` section
- Follow semantic versioning (MAJOR.MINOR.PATCH)
## Task Management
- **When completing tasks, mark them as done** - if you finish any task with a checkbox anywhere in project documentation, check it off as completed `[ ]` → `[x]`
- **Track all work** - this applies to tasks in `PROJECT.md` (TODO section, Development Roadmap, any checklists) and other documentation
- **Update documentation** - when completing changes, update relevant sections in `PROJECT.md`, `CHANGELOG.md`, and architecture diagrams
- **Keep task lists current** - completed items with `[x]` stay visible to show progress history
+10
View File
@@ -0,0 +1,10 @@
## First-time setup
**At the start of every new session, read all of the following files before doing anything else:**
- `CLAUDE.md` (this file)
- `AGENTS.md`
- `PROJECT.md`
- `CHANGELOG.md`
- `DESIGN_DOCUMENT.md`
+8
View File
@@ -0,0 +1,8 @@
---
name: changelog
description: Updates changelog in project
---
Take known info and make changes to CHANGELOG.md to make them up-to-date.
Ignore changes to: `docs/`, `CONTEXT.md`, `Documentation_AI.md`, `Documentation_human.md` — documentation and context files are not logged in the changelog.
+5
View File
@@ -0,0 +1,5 @@
---
name: check
description: Check for failed tests
---
Try running tests and investigate failed results
+12
View File
@@ -0,0 +1,12 @@
---
name: commit
description: Updates changelog and proposes a concise verbal git commit message
---
1. Run the changelog skill: read git log and staged changes, then update CHANGELOG.md accordingly (same as /changelog).
2. Propose a single-line verbal commit message:
- Concise, verbal style — e.g. "Add X", "Fix Y", "Refactor Z"
- NOT filename-style — never "update_something.py" or "changes to foo"
- In English
- Do NOT run git commit — only propose the message and wait for user confirmation.
+38
View File
@@ -0,0 +1,38 @@
---
name: context
description: Compress docs/ into CONTEXT.md at project root — minimum tokens, lossless
---
Read every `.md` file in `docs/`. Generate `CONTEXT.md` at the project root.
## Goal
Lossless compression of `docs/` into a single file optimised for LLM context window use.
Every public function, class, constant, invariant, file path, and edge case from `docs/` must be present.
Target: CONTEXT.md ≈ 4050% byte size of combined `docs/` input.
## Format rules
- Symbol legend at top: `Legend: → returns * required ? optional @ located at`
- Tables over paragraphs — always
- Compact signature notation: `f(a:T, b:T) → T @ src/foo.py`
- Pipe unions: `A | B | C`
- Section references: §0, §1, … — state each fact once, reference elsewhere
- Inline conditions: `if X: Y; else: Z`
- No prose, no motivation, no examples that just illustrate a stated rule
- No headings deeper than 3 levels
## Sections
- §0 Module map — path + 1-line role
- §1 Data types — every class: fields, types, invariants
- §2 Public API — every public function/method: compact signature + constraints
- §3 Constants — table: name, value, file, where used
- §4 Workflows — compact arrow notation
- §5 Configuration — env vars, defaults
- §6 Edge cases & invariants — one row per rule, exhaustive
- §7 Build / run / test — exact commands
## When to skip
If `CONTEXT.md` exists and no file in `docs/` is newer than it: print `context: in sync` and stop.
+5
View File
@@ -0,0 +1,5 @@
---
name: documentation
description: Updates documentation in project
---
Create or update documentation of project in docs/ folder. Documentation should contain description of each part of program and documentation of each function. Separate documents for each module. Write in markdown format.
+20
View File
@@ -0,0 +1,20 @@
# Changelog
Document all notable changes to the project, grouped by version and release date.
## Format
Each version entry uses these sections (include only those that apply):
- **Added** — new features
- **Changed** — changes to existing functionality
- **Fixed** — bug fixes
- **Removed** — removed features
- **Dependencies** — added, updated, or removed dependencies
## Rules
- Follow semantic versioning: `MAJOR.MINOR.PATCH`
- Newest version goes at the top
- Always update this file before bumping the version in `pyproject.toml`
- Document changes as they are made, not all at once at release time
+5
View File
@@ -0,0 +1,5 @@
# PROJECT.md
This file is project-specific. Only include information directly related to the concrete project — goals, current state, architecture decisions, known issues, and tasks.
Do not put general guidelines or reusable documentation here.
+212
View File
@@ -0,0 +1,212 @@
# Python Development Guidelines
**Document Version:** v8
> **Note on Versioning:**
> - This document version is independent — reused across projects
> - **Project version** source of truth: `pyproject.toml`
> - Version propagates: `pyproject.toml` → `constants.py` → code
> - `CHANGELOG.md` uses project version from `pyproject.toml`
## Related Documents
- **README.md** — Project overview, tool descriptions, build instructions
- **AGENTS.md** — Rules for AI assistants
- **PROJECT.md** — Project goals and current state
- **CHANGELOG.md** — Version history
### Documentation Organization
All detailed documentation of features and systems belongs in the `docs/` folder, not in the project root.
The root directory contains only the core documents: `DESIGN_DOCUMENT.md`, `AGENTS.md`, `PROJECT.md`, `CHANGELOG.md`.
---
## 1. Code Style
- **PEP8** with 150-character lines (Ruff)
- **4 spaces** indentation
- **snake_case** functions/variables, **PascalCase** classes, **SCREAMING_SNAKE_CASE** constants
- **Type hints** required on all functions
- **Import order**: stdlib → third-party → local
---
## 2. SOLID Principles
- **SRP** — One class = one responsibility
- **OCP** — Open for extension, closed for modification
- **LSP** — Subclasses substitutable for parents
- **ISP** — Small interfaces over large ones
- **DIP** — Depend on abstractions
---
## 3. Dependency Injection
Pass dependencies via constructor. Never instantiate dependencies inside a class.
---
## 4. Protocols Over Inheritance
Prefer `typing.Protocol` and composition over class inheritance.
---
## 5. Data Classes
Use `@dataclass` for internal data structures, `pydantic.BaseModel` for data that requires validation.
---
## 6. Logging and Console Output
### Logging — loguru
Use **loguru** for all internal logging. Never log secrets, passwords, tokens, or API keys.
#### Log sinks
| Sink | Level | Format |
|------|-------|--------|
| File `logs/{AppName}_{time}.log` | `DEBUG` | full (timestamp + level + message) |
| stdout | `INFO` | full |
File sink retains **max 10 log files** (`retention=10`). No rotation by size — each run creates a new file via `{time}` in the filename.
The `DEBUG` sink is only active when `constants.DEBUG` is `True` (controlled by `ENV_DEBUG=true` in `.env`).
Additional sinks (e.g. GUI log panels) may be added per project as needed.
#### Log levels
| Level | When to use |
|-------|-------------|
| `DEBUG` | Per-item detail: individual file reads/writes, cache hits, per-row operations |
| `INFO` | User-visible milestones: file loaded, process started/finished, file saved |
| `WARNING` | Recoverable issues: fallback used, unexpected but non-fatal state |
| `ERROR` | Failures the user must know about: missing file, failed save, missing config — operation cannot continue |
### Console output — print()
`print()` is **allowed** for direct user-facing console communication: input prompts, progress lines, and result summaries. This applies to console tools that interact with the user through stdin/stdout.
`print()` is **not** a substitute for loguru. It must not be used for debugging or internal event tracking.
---
## 7. Environment and Secrets
- Secrets in `.env` file; controlled by `ENV_DEBUG=true/false`
- Load via `python-dotenv` and `os.getenv()`
- Never commit `.env`
---
## 8. Error Handling
Define specific exception types. Use a fail-fast approach — surface errors early rather than silently continuing.
---
## 9. Testing
- **pytest** only — no `unittest`, no `TestCase` classes, no `self.assert*`
- Arrange-Act-Assert pattern
- Test naming: `test_<action>_<context>`
---
## 10. Tooling
| Tool | Purpose |
|------|---------|
| **Ruff** | Formatting and linting |
| **mypy** | Static type checking |
| **pytest** | Testing |
Run before every commit:
```bash
poetry run ruff check
poetry run mypy
```
---
## 11. Poetry
```bash
poetry install # Install all dependencies
poetry add <pkg> # Add runtime dependency
poetry add --group dev <pkg> # Add dev dependency
poetry remove <pkg> # Remove dependency
poetry run <cmd> # Run command in virtualenv
```
Never edit `pyproject.toml` directly to add or remove dependencies.
---
## 12. Project Structure
```
project/
├── entry_point.py # Entry point(s) — named by purpose or tool name
├── src/ # All application modules
├── tests/ # Tests
├── docs/ # Detailed documentation
├── .venv/ # Virtual environment (managed by Poetry)
└── pyproject.toml # Project config and dependencies
```
A project may have multiple entry points (e.g. `cli.py`, `gui.py`, or per-tool scripts).
---
## 13. Distribution and Deployment
When a project is distributed as a standalone executable (no Python required on target machine):
- Use **PyInstaller** to compile each entry point into a single `.exe`
- Each tool has its own `.spec` file in the project root
- All console tools must use `console=True` in the `.spec` — tools rely on `input()` and `print()` for user interaction
- Compiled executables are stored in `dist/` and **committed to the repository** — the repository serves as the distribution channel for internal teams
- `.gitignore` must **not** exclude `dist/` in projects that use this deployment model
Build command:
```bash
poetry run pyinstaller ToolName.spec
```
> This section applies only to projects that produce standalone executables. Skip for libraries or web services.
---
## 14. Versioning
- Follow **semantic versioning**: `MAJOR.MINOR.PATCH`
- Version is defined in `pyproject.toml` under `[project]`
- Always ask before bumping the version — never increment automatically
- Update `CHANGELOG.md` before bumping the version
---
## 15. Documentation and Task Management
- Keep `PROJECT.md` and `CHANGELOG.md` up to date when making changes
- Document architectural changes in this file or in `docs/`
### Task notation
Tasks are written as single-line comments directly in code, or in `PROJECT.md` for cross-cutting concerns:
```python
# TODO: one-liner description of a task to be done
# FIXME: one-liner description of a known bug to be fixed
```
No other task format is used — no checkboxes, no numbered lists in documentation.
If a `# TODO:` comment already exists at a specific location in code, do not repeat it in `PROJECT.md`.
+260
View File
@@ -0,0 +1,260 @@
# Python Library Development Guidelines
**Document Version:** v1
> **Note on Versioning:**
> - This document version is independent — reused across projects
> - **Project version** source of truth: `pyproject.toml` under `[project]`
> - `CHANGELOG.md` uses project version from `pyproject.toml`
## Related Documents
- **README.md** — Project overview, public API description, installation and usage examples
- **AGENTS.md** — Rules for AI assistants
- **PROJECT.md** — Project goals and current state
- **CHANGELOG.md** — Version history
### Documentation Organization
All detailed documentation of features and systems belongs in the `docs/` folder, not in the project root.
The root directory contains only the core documents: `DESIGN_DOCUMENT_MODULE.md`, `AGENTS.md`, `PROJECT.md`, `CHANGELOG.md`.
---
## 1. Code Style
- **PEP8** with 150-character lines (Ruff)
- **4 spaces** indentation
- **snake_case** functions/variables, **PascalCase** classes, **SCREAMING_SNAKE_CASE** constants
- **Type hints** required on all functions
- **Import order**: stdlib → third-party → local
---
## 2. SOLID Principles
- **SRP** — One class = one responsibility
- **OCP** — Open for extension, closed for modification
- **LSP** — Subclasses substitutable for parents
- **ISP** — Small interfaces over large ones
- **DIP** — Depend on abstractions
---
## 3. Dependency Injection
Pass dependencies via constructor. Never instantiate dependencies inside a class.
---
## 4. Protocols Over Inheritance
Prefer `typing.Protocol` and composition over class inheritance.
---
## 5. Data Classes
Use `@dataclass` for internal data structures, `pydantic.BaseModel` for data that requires validation.
---
## 6. Logging
This is a library. Libraries must **never configure logging sinks** — that is the responsibility of the consuming application.
### Usage in library code
```python
from loguru import logger
def some_function() -> None:
logger.debug("Detail message")
logger.info("Milestone message")
```
Always use the module-level `logger` from loguru directly. Never call `logger.add()` or `logger.remove()` inside library code.
### Behavior for consumers
Loguru has a default sink to `stderr` enabled. Consumers who also use loguru get library logs automatically in their configured sinks. Consumers who want to suppress or filter library logs use the package name as the identifier:
```python
from loguru import logger
logger.disable("<package_name>") # suppress all
logger.add(sys.stderr, filter={"<package_name>": "WARNING"}) # WARNING and above only
logger.enable("<package_name>") # re-enable
```
This must be documented in `README.md`.
### Rules
- Never call `logger.add()` inside library code — no file sinks, no stdout sinks
- Never call `logger.remove()` inside library code
- Never log secrets, passwords, tokens, or API keys
- Never use `print()` inside library code — not for debugging, not for output
#### Log levels
| Level | When to use |
|-------|-------------|
| `DEBUG` | Per-item detail: individual operations, cache hits, internal state |
| `INFO` | Significant milestones visible to the consuming application |
| `WARNING` | Recoverable issues: fallback used, unexpected but non-fatal state |
| `ERROR` | Failures the caller must know about — operation cannot continue |
---
## 7. Environment and Secrets
- Libraries do not use `.env` files or `python-dotenv`
- Configuration is passed by the caller via arguments or constructor parameters
- Never read `os.getenv()` inside library code unless explicitly documented as a supported configuration mechanism
---
## 8. Error Handling
Define specific exception types in `src/<package>/exceptions.py`. Use a fail-fast approach — surface errors early rather than silently continuing. All public exceptions must be exported from the top-level `__init__.py`.
---
## 9. Testing
- **pytest** only — no `unittest`, no `TestCase` classes, no `self.assert*`
- Arrange-Act-Assert pattern
- Test naming: `test_<action>_<context>`
- Do not commit `poetry.lock` — this is a library; consumers pin their own dependencies
---
## 10. Tooling
| Tool | Purpose |
|------|---------|
| **Ruff** | Formatting and linting |
| **mypy** | Static type checking |
| **pytest** | Testing |
Run before every commit:
```bash
poetry run ruff check
poetry run mypy
poetry run pytest
```
---
## 11. Poetry
```bash
poetry install # Install all dependencies
poetry add <pkg> # Add runtime dependency
poetry add --group dev <pkg> # Add dev dependency
poetry remove <pkg> # Remove dependency
poetry run <cmd> # Run command in virtualenv
poetry build # Build sdist and wheel into dist/
poetry publish # Publish to PyPI
```
Never edit `pyproject.toml` directly to add or remove dependencies.
### pyproject.toml configuration for a library
```toml
[project]
name = "your-library"
version = "0.1.0"
description = "Short description"
requires-python = ">=3.x"
dependencies = []
[tool.poetry]
packages = [{include = "your_library", from = "src"}]
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
```
Do **not** add `[tool.poetry.scripts]` — libraries have no entry points.
### poetry.lock
Do **not** commit `poetry.lock` for libraries. It is only committed for applications. Add `poetry.lock` to `.gitignore`.
---
## 12. Project Structure
```
project/
├── src/
│ └── your_library/
│ ├── __init__.py # Public API — export everything the caller needs
│ ├── exceptions.py # All public exception types
│ └── ... # Internal modules
├── tests/ # Tests
├── docs/ # Detailed documentation
├── .venv/ # Virtual environment (managed by Poetry)
└── pyproject.toml # Project config and dependencies
```
- No entry point scripts in the project root — this is a library, not an application
- `__init__.py` defines the public API; callers import from the top-level package only
---
## 13. Public API
- Everything intended for external use must be exported from `src/<package>/__init__.py`
- Use `__all__` to explicitly declare the public surface
- Internal modules are prefixed with `_` or kept unexported
- Public API must be stable across patch versions; breaking changes require a major version bump
---
## 14. Distribution
Build and publish with Poetry:
```bash
poetry build # Creates dist/*.tar.gz and dist/*.whl
poetry publish # Publishes to PyPI (requires credentials)
```
`dist/` is **not committed** to the repository — add it to `.gitignore`.
---
## 15. Versioning
- Follow **semantic versioning**: `MAJOR.MINOR.PATCH`
- Version is defined in `pyproject.toml` under `[project]`
- Always ask before bumping the version — never increment automatically
- Update `CHANGELOG.md` before bumping the version
- Breaking changes to the public API require a major version bump
---
## 16. Documentation and Task Management
- Keep `PROJECT.md` and `CHANGELOG.md` up to date when making changes
- `README.md` must contain installation instructions and usage examples for the public API
- Document architectural changes in this file or in `docs/`
### Task notation
Tasks are written as single-line comments directly in code, or in `PROJECT.md` for cross-cutting concerns:
```python
# TODO: one-liner description of a task to be done
# FIXME: one-liner description of a known bug to be fixed
```
No other task format is used — no checkboxes, no numbered lists in documentation.
If a `# TODO:` comment already exists at a specific location in code, do not repeat it in `PROJECT.md`.
+41
View File
@@ -0,0 +1,41 @@
# Template Generation Request
Create a `template/` folder in project root with reusable files for new Python projects.
## Required Structure
```
template/
├── .env # Environment variables (sample)
├── .gitignore # Git ignore rules
├── AGENTS.md # AI assistant rules
├── CHANGELOG.md # Changelog template
├── DESIGN_DOCUMENT.md # Development guidelines
├── PROJECT.md # Project documentation template
├── main.py # Entry point with loguru
├── pyproject.toml # Poetry config (ruff, mypy, pytest)
├── src/
│ ├── __init__.py
│ └── core/
│ ├── __init__.py
│ ├── _version.py # Version fallback for PyInstaller
│ └── constants.py # Version extraction from toml + DEBUG mode
└── tests/
├── __init__.py
└── test_constants.py # Basic test
```
## Key Features
- **Version extraction** from `pyproject.toml` with `_version.py` fallback for PyInstaller builds
- **DEBUG mode** via `ENV_DEBUG=true` in `.env` (adds " DEV" suffix to version)
- **loguru** for logging (never print)
- **Poetry** for dependency management
- **pytest** for testing (no unittest)
- **ruff + mypy** for linting and type checking
## Rules
- No `.example` suffixes - the folder itself is the separator
- Generic/reusable format
- Keep files simple and minimal
+66
View File
@@ -0,0 +1,66 @@
import os
import sys
from pathlib import Path
from dotenv import load_dotenv
from src.constants import VERSION
load_dotenv()
print("=" * 50)
print("PREBUILD CONFIGURATION")
print("=" * 50)
# Check if running in virtual environment
project_root = Path(__file__).parent
expected_venv_path = project_root / ".venv"
current_executable = Path(sys.executable)
print(f"\nPython executable: {sys.executable}")
is_correct_venv = False
try:
current_executable.relative_to(expected_venv_path)
is_correct_venv = True
except ValueError:
is_correct_venv = False
if is_correct_venv:
print("✓ Correct environment selected for building")
else:
print("✗ Wrong environment selected")
print(f" Expected: {expected_venv_path}")
print(f" Current: {current_executable.parent.parent}")
print(f"✓ Version: {VERSION}")
env_debug = os.getenv("ENV_DEBUG", "false").lower() == "true"
console_mode = env_debug
default_spec = Path(__file__).parent.name + ".spec"
spec_filename = os.getenv("ENV_BUILD_SPEC", default_spec)
print(f"\n{'-' * 50}")
print("BUILD SETTINGS")
print(f"{'-' * 50}")
print(f"ENV_DEBUG: {env_debug}")
print(f"Console mode: {console_mode}")
print(f"Spec file: {spec_filename}")
spec_path = Path(__file__).parent / spec_filename
if spec_path.exists():
with open(spec_path, "r", encoding="utf-8") as f:
spec_content = f.read()
if f"console={not console_mode}" in spec_content:
new_spec_content = spec_content.replace(
f"console={not console_mode}",
f"console={console_mode}"
)
with open(spec_path, "w", encoding="utf-8") as f:
f.write(new_spec_content)
print(f"✓ Updated {spec_filename}: console={console_mode}")
else:
print(f"{spec_filename} already configured: console={console_mode}")
else:
print(f"{spec_filename} not found!")
print(f"{'-' * 50}\n")
View File
+7
View File
@@ -0,0 +1,7 @@
"""Auto-generated version - DO NOT EDIT MANUALLY!
This file is automatically generated from pyproject.toml.
Serves as fallback for cases when TOML is not available.
"""
__version__ = "0.1.0"
+81
View File
@@ -0,0 +1,81 @@
"""
Generic application constants template.
Usage in your project:
1. Copy this file to src/constants.py
2. Fill in APP_NAME and APP_FULL_NAME
3. Import VERSION, APP_TITLE, DEFAULT_DEBUG where needed
Version loading priority:
1. pyproject.toml [project] version (preferred)
2. src/_version.py __version__ (generated fallback for frozen builds)
3. "0.0.0" (last resort)
Debug mode:
Controlled exclusively via .env: ENV_DEBUG=true
Accepted true-values: true, 1, yes (case-insensitive)
"""
import os
import tomllib
from pathlib import Path
from dotenv import load_dotenv
from loguru import logger
load_dotenv()
# ---------------------------------------------------------------------------
# Version
# ---------------------------------------------------------------------------
_ROOT = Path(__file__).parent.parent
_PYPROJECT = _ROOT / "pyproject.toml"
_VERSION_FILE = Path(__file__).parent / "_version.py"
def _load_version() -> str:
# 1. pyproject.toml
try:
with open(_PYPROJECT, "rb") as f:
version = tomllib.load(f)["project"]["version"]
# Write fallback for frozen/PyInstaller builds
_VERSION_FILE.write_text(
f'"""Auto-generated — do not edit manually."""\n__version__ = "{version}"\n',
encoding="utf-8",
)
return version
except (FileNotFoundError, KeyError):
pass
# 2. _version.py
try:
from src._version import __version__ # type: ignore[import]
return __version__
except ImportError:
pass
# 3. last resort
return "0.0.0"
# ---------------------------------------------------------------------------
# Debug mode
# ---------------------------------------------------------------------------
def _load_debug() -> bool:
return os.getenv("ENV_DEBUG", "false").lower() in ("true", "1", "yes")
# ---------------------------------------------------------------------------
# Public constants ← fill in APP_NAME / APP_FULL_NAME for each project
# ---------------------------------------------------------------------------
APP_NAME: str = "MyApp"
APP_FULL_NAME: str = "My Application"
_VERSION_NUMBER: str = _load_version()
DEFAULT_DEBUG: bool = _load_debug()
VERSION: str = f"v{_VERSION_NUMBER}" + ("DEV" if DEFAULT_DEBUG else "")
APP_TITLE: str = f"{APP_FULL_NAME} {VERSION}"
View File
+141
View File
@@ -0,0 +1,141 @@
"""Tests for constants module."""
import re
from pathlib import Path
from unittest.mock import mock_open, patch
import pytest
from src.constants import (
APP_NAME,
APP_TITLE,
APP_VERSION,
ENV_DEBUG,
get_debug_mode,
get_version,
)
# ---------------------------------------------------------------------------
# get_version()
# ---------------------------------------------------------------------------
def test_get_version_returns_string() -> None:
"""get_version() should return a string."""
assert isinstance(get_version(), str)
def test_get_version_semver_format() -> None:
"""get_version() should return a semver-like string X.Y.Z."""
version = get_version()
assert re.match(r"^\d+\.\d+\.\d+", version), f"Not semver: {version!r}"
def test_get_version_fallback_when_toml_missing(tmp_path: Path) -> None:
"""get_version() returns '0.0.0-unknown' when pyproject.toml and _version.py are both missing."""
missing = tmp_path / "nonexistent.toml"
with patch("src.constants._PYPROJECT_PATH", missing):
result = get_version()
# Either fallback _version.py exists (from previous run) or returns unknown
assert isinstance(result, str)
assert len(result) > 0
def test_get_version_unknown_fallback(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""get_version() returns '0.0.0-unknown' when all sources are unavailable."""
missing = tmp_path / "nonexistent.toml"
monkeypatch.setattr("src.constants._PYPROJECT_PATH", missing)
# Patch _version import to also fail
with patch("src.constants.Path.write_text", side_effect=OSError):
with patch.dict("sys.modules", {"src._version": None}):
result = get_version()
assert isinstance(result, str)
# ---------------------------------------------------------------------------
# get_debug_mode()
# ---------------------------------------------------------------------------
def test_get_debug_mode_returns_bool() -> None:
"""get_debug_mode() should always return a bool."""
assert isinstance(get_debug_mode(), bool)
def test_get_debug_mode_true(monkeypatch: pytest.MonkeyPatch) -> None:
"""get_debug_mode() returns True when ENV_DEBUG=true."""
monkeypatch.setenv("ENV_DEBUG", "true")
assert get_debug_mode() is True
def test_get_debug_mode_true_variants(monkeypatch: pytest.MonkeyPatch) -> None:
"""get_debug_mode() accepts '1' and 'yes' as truthy values."""
for value in ("1", "yes", "YES", "True", "TRUE"):
monkeypatch.setenv("ENV_DEBUG", value)
assert get_debug_mode() is True, f"Expected True for ENV_DEBUG={value!r}"
def test_get_debug_mode_false(monkeypatch: pytest.MonkeyPatch) -> None:
"""get_debug_mode() returns False when ENV_DEBUG=false."""
monkeypatch.setenv("ENV_DEBUG", "false")
assert get_debug_mode() is False
def test_get_debug_mode_false_when_unset(monkeypatch: pytest.MonkeyPatch) -> None:
"""get_debug_mode() returns False when ENV_DEBUG is not set."""
monkeypatch.delenv("ENV_DEBUG", raising=False)
assert get_debug_mode() is False
# ---------------------------------------------------------------------------
# Module-level constants
# ---------------------------------------------------------------------------
def test_env_debug_is_bool() -> None:
"""ENV_DEBUG should be a bool."""
assert isinstance(ENV_DEBUG, bool)
def test_app_version_is_string() -> None:
"""APP_VERSION should be a string."""
assert isinstance(APP_VERSION, str)
def test_app_version_semver_format() -> None:
"""APP_VERSION should follow semver format X.Y.Z."""
assert re.match(r"^\d+\.\d+\.\d+", APP_VERSION), f"Not semver: {APP_VERSION!r}"
def test_app_name_value() -> None:
"""APP_NAME should be 'X4 SavEd'."""
assert APP_NAME == "X4 SavEd"
def test_app_title_contains_name_and_version() -> None:
"""APP_TITLE should contain APP_NAME and APP_VERSION."""
assert APP_NAME in APP_TITLE
assert APP_VERSION in APP_TITLE
def test_app_title_dev_suffix_when_debug(monkeypatch: pytest.MonkeyPatch) -> None:
"""APP_TITLE ends with '-DEV' when ENV_DEBUG is True."""
import importlib
import src.constants as consts
monkeypatch.setenv("ENV_DEBUG", "true")
monkeypatch.setattr(consts, "ENV_DEBUG", True)
title = f"{consts.APP_NAME} v{consts.APP_VERSION}" + ("-DEV" if True else "")
assert title.endswith("-DEV")
def test_app_title_no_dev_suffix_when_not_debug(monkeypatch: pytest.MonkeyPatch) -> None:
"""APP_TITLE does not end with '-DEV' when ENV_DEBUG is False."""
import src.constants as consts
monkeypatch.setattr(consts, "ENV_DEBUG", False)
title = f"{consts.APP_NAME} v{consts.APP_VERSION}" + ("-DEV" if False else "")
assert not title.endswith("-DEV")
+174
View File
@@ -0,0 +1,174 @@
# 🏷️ Tagger
Desktopová aplikace pro správu a organizaci souborů pomocí hierarchických tagů (štítků).
## ✨ Hlavní funkce
- 📁 Rekurzivní procházení složek
- 🏷️ Hierarchické tagy (kategorie/název)
- 🔍 Filtrování podle tagů a textu
- 💾 Metadata v JSON souborech (.!tag)
- 🎬 Automatická detekce rozlišení videí (ffprobe)
- 🎨 Dvě verze GUI: klasické a moderní (qBittorrent-style)
## 🚀 Rychlý start
```bash
# Instalace závislostí
poetry install
# Spuštění (moderní GUI)
poetry run python Tagger_modern.py
# Nebo klasické GUI
poetry run python Tagger.py
```
## 📸 Screenshot
### Moderní GUI (qBittorrent-style)
```
┌─────────────────────────────────────────────────────┐
│ 📁 Otevřít │ 🔄 │ 🏷️ │ 📅 🔍 [____] Toolbar
├────────────┬────────────────────────────────────────┤
│ 📂 Štítky │ Název │Datum│Štítky│Velikost │
│ ├─📁 Stav │ file1.txt│2025 │HD │1.2 MB │
│ │ ☑ Nové │ file2.mp4│ │4K │15 MB │
│ ├─📁 Video│ file3.jpg│ │RAW │845 KB │
│ │ ☐ HD │ │
├────────────┴────────────────────────────────────────┤
│ Připraven 3 vybráno │ 125 souborů │
└─────────────────────────────────────────────────────┘
```
## 🎯 Použití
1. **Otevři složku** - Načti soubory ze složky (rekurzivně)
2. **Vytvoř tagy** - Hierarchická struktura (kategorie → tagy)
3. **Přiřaď tagy** - Označ soubory, vyber tagy
4. **Filtruj** - Klikni na tagy pro filtrování souborů
5. **Vyhledávej** - Textové vyhledávání v názvech
## ⌨️ Keyboard Shortcuts (moderní GUI)
- `Ctrl+O` - Otevřít složku
- `Ctrl+T` - Přiřadit tagy
- `Ctrl+D` - Nastavit datum
- `F5` - Refresh
- `Del` - Smazat z indexu
## 🏗️ Architektura
```
┌─────────────────────────────────┐
│ Presentation (UI) │ ← Tkinter GUI
├─────────────────────────────────┤
│ Business Logic │ ← FileManager, TagManager
├─────────────────────────────────┤
│ Data Layer │ ← File, Tag models
├─────────────────────────────────┤
│ Persistence │ ← JSON .!tag soubory
└─────────────────────────────────┘
```
## 📁 Struktura projektu
```
Tagger/
├── Tagger.py # Entry point (klasické GUI)
├── Tagger_modern.py # Entry point (moderní GUI)
├── PROJECT_NOTES.md # ⭐ Kompletní dokumentace
├── src/
│ ├── core/ # Business logika
│ │ ├── file.py
│ │ ├── tag.py
│ │ ├── file_manager.py
│ │ └── tag_manager.py
│ └── ui/
│ ├── gui.py # Klasické GUI
│ └── gui_modern.py # Moderní GUI
└── tests/ # 116 testů
```
## 🧪 Testování
```bash
# Všechny testy (116 testů, 100% core coverage)
poetry run pytest tests/ -v
# S coverage report
poetry run pytest tests/ --cov=src/core --cov-report=html
```
## 📝 Dokumentace
**Veškerá dokumentace je v jednom souboru:**
👉 **[PROJECT_NOTES.md](PROJECT_NOTES.md)** ⭐
Obsahuje:
- Kompletní dokumentaci projektu
- Architektonická rozhodnutí (ADR)
- Coding standards
- Git workflow
- Known issues & TODO
- Debugování tipy
- Pravidla pro AI asistenty
## 🛠️ Technologie
- **Python:** 3.12
- **GUI:** Tkinter (standard library)
- **Dependencies:** Pillow (PIL)
- **Package manager:** Poetry
- **Testing:** pytest
## 📊 Metriky
- **Řádky kódu:** ~1060 Python LOC
- **Testy:** 116 (všechny ✅)
- **Test coverage:** 100% core modulů
- **GUI verze:** 2 (klasická + moderní)
## 🎯 Design Decisions
### Proč JSON místo databáze?
- ✅ Jednoduchý backup (copy složky)
- ✅ Git-friendly (plain text)
- ✅ Portable (žádné DB dependencies)
- ✅ Metadata zůstanou při přesunu souboru
### Proč Tkinter?
- ✅ Standard library (žádné extra deps)
- ✅ Cross-platform
- ✅ Dobře dokumentované
### Proč Poetry?
- ✅ Deterministické buildy (poetry.lock)
- ✅ Dev dependencies oddělené
- ✅ Moderní nástroj
## 🐛 Known Issues
- Git merge konflikty s poetry.lock při merge devel→feature
- Dlouhé operace (ffprobe) blokují UI - TODO: threading
## 🚀 Plánované features
- [ ] Progress bar pro dlouhé operace
- [ ] Undo/Redo mechanismus
- [ ] Export do CSV/Excel
- [ ] Dark mode theme
- [ ] Drag & drop souborů
## 📄 License
MIT License
## 👤 Autor
honza
---
**Pro detailní dokumentaci viz [PROJECT_NOTES.md](PROJECT_NOTES.md)**
+7
View File
@@ -0,0 +1,7 @@
## NODE_EXTRA_CA_CERTS
1. `Win + R``sysdm.cpl`**Advanced → Environment Variables**
2. Pod **User variables****New**
- Name: `NODE_EXTRA_CA_CERTS`
- Value: `C:\cesta\k\zscaler.cer`
3. OK → restartovat VSCode
@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIJANu+mC2Jt3uTMA0GCSqGSIb3DQEBCwUAMIGhMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2Ux
FTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMMWnNjYWxlciBJbmMuMRgw
FgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG9w0BCQEWE3N1cHBvcnRA
enNjYWxlci5jb20wHhcNMTQxMjE5MDAyNzU1WhcNNDIwNTA2MDAyNzU1WjCBoTEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBK
b3NlMRUwEwYDVQQKEwxac2NhbGVyIEluYy4xFTATBgNVBAsTDFpzY2FsZXIgSW5j
LjEYMBYGA1UEAxMPWnNjYWxlciBSb290IENBMSIwIAYJKoZIhvcNAQkBFhNzdXBw
b3J0QHpzY2FsZXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
qT7STSxZRTgEFFf6doHajSc1vk5jmzmM6BWuOo044EsaTc9eVEV/HjH/1DWzZtcr
fTj+ni205apMTlKBW3UYR+lyLHQ9FoZiDXYXK8poKSV5+Tm0Vls/5Kb8mkhVVqv7
LgYEmvEY7HPY+i1nEGZCa46ZXCOohJ0mBEtB9JVlpDIO+nN0hUMAYYdZ1KZWCMNf
5J/aTZiShsorN2A38iSOhdd+mcRM4iNL3gsLu99XhKnRqKoHeH83lVdfu1XBeoQz
z5V6gA3kbRvhDwoIlTBeMa5l4yRdJAfdpkbFzqiwSgNdhbxTHnYYorDzKfr2rEFM
dsMU0DHdeAZf711+1CunuQIDAQABo4IBCjCCAQYwHQYDVR0OBBYEFLm33UrNww4M
hp1d3+wcBGnFTpjfMIHWBgNVHSMEgc4wgcuAFLm33UrNww4Mhp1d3+wcBGnFTpjf
oYGnpIGkMIGhMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8G
A1UEBxMIU2FuIEpvc2UxFTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMM
WnNjYWxlciBJbmMuMRgwFgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG
9w0BCQEWE3N1cHBvcnRAenNjYWxlci5jb22CCQDbvpgtibd7kzAMBgNVHRMEBTAD
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAw0NdJh8w3NsJu4KHuVZUrmZgIohnTm0j+
RTmYQ9IKA/pvxAcA6K1i/LO+Bt+tCX+C0yxqB8qzuo+4vAzoY5JEBhyhBhf1uK+P
/WVWFZN/+hTgpSbZgzUEnWQG2gOVd24msex+0Sr7hyr9vn6OueH+jj+vCMiAm5+u
kd7lLvJsBu3AO3jGWVLyPkS3i6Gf+rwAp1OsRrv3WnbkYcFf9xjuaf4z0hRCrLN2
xFNjavxrHmsH8jPHVvgc1VD0Opja0l/BRVauTrUaoW6tE+wFG5rEcPGS80jjHK4S
pB5iDj2mUZH1T8lzYtuZy0ZPirxmtsk3135+CKNa2OCAhhFjE0xd
-----END CERTIFICATE-----