295 lines
11 KiB
TOML
295 lines
11 KiB
TOML
# ©AngelaMos | 2026
|
|
# pyproject.toml
|
|
#
|
|
# This file is the "instruction manual" for our Python project. Every
|
|
# modern Python project has one. It tells tools like uv, pip, pytest,
|
|
# ruff, mypy, and pylint:
|
|
#
|
|
# - What our project is called
|
|
# - Which third-party libraries we depend on
|
|
# - How to build and install it
|
|
# - How to lint, type-check, and test it
|
|
#
|
|
# The file format is called TOML — a simple, human-readable config
|
|
# language. Square brackets like [project] start a "table" (a section).
|
|
# Lines like name = "..." are key-value pairs inside that table.
|
|
#
|
|
# Read this top-to-bottom. Each section has a short comment explaining
|
|
# what it does and why it is here.
|
|
|
|
|
|
# =============================================================================
|
|
# [project] — the metadata that describes WHAT this project is
|
|
# =============================================================================
|
|
# This section is standardized across the whole Python ecosystem (PEP 621).
|
|
# Anyone who runs `pip install` or `uv sync` reads from here.
|
|
[project]
|
|
# The name people will install this package under.
|
|
# Must be unique on PyPI if we ever publish there.
|
|
name = "password-vault"
|
|
|
|
# Semantic version: MAJOR.MINOR.PATCH.
|
|
# 1.0.0 means "first stable release."
|
|
# When we add features → bump MINOR (1.1.0). When we break things → MAJOR.
|
|
version = "1.0.0"
|
|
|
|
# One-line description that shows up in `pip show` and on PyPI.
|
|
description = "Beginner-friendly encrypted password manager (Argon2id + AES-256-GCM)"
|
|
|
|
# The minimum Python version this project supports.
|
|
# >=3.13 means "Python 3.13 or anything newer."
|
|
# We need 3.13 because we use modern type-hint syntax (X | None).
|
|
requires-python = ">=3.13"
|
|
|
|
# Who wrote it. Shows up in package metadata.
|
|
authors = [
|
|
{name = "CarterPerez-dev", email = "support@certgames.com"}
|
|
]
|
|
|
|
# The README file is shown on PyPI and in `pip show`.
|
|
readme = "README.md"
|
|
|
|
# AGPL-3.0 means: anyone can use it, but if they modify and run it as a
|
|
# service, they must publish their changes. It protects the project
|
|
# from being privatized.
|
|
license = {text = "AGPL-3.0-or-later"}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# dependencies — third-party libraries we MUST have at runtime
|
|
# -----------------------------------------------------------------------------
|
|
# When a user runs `pip install password-vault`, these get installed too.
|
|
# The string format is "<name><operator><version>". We use ranges so we
|
|
# get bug fixes (>=) but never an incompatible major version (<).
|
|
dependencies = [
|
|
# argon2-cffi: implements Argon2id, the modern password-hashing
|
|
# algorithm we use to turn the master password into an encryption key.
|
|
"argon2-cffi>=25.1.0",
|
|
|
|
# cryptography: provides AES-256-GCM, the actual encryption that
|
|
# scrambles vault contents. Maintained by the Python Cryptographic
|
|
# Authority — the gold-standard library, audited and trusted.
|
|
"cryptography>=48.0.0",
|
|
|
|
# typer: builds nice CLIs from regular Python functions.
|
|
# Lets us write `add`, `get`, `list` commands with auto-generated help.
|
|
"typer>=0.25.1",
|
|
|
|
# rich: pretty terminal output — colors, tables, panels, prompts.
|
|
# Makes the CLI pleasant to use without writing a bunch of formatting.
|
|
"rich>=15.0.0",
|
|
]
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# optional-dependencies — extra libraries that are NOT needed at runtime
|
|
# -----------------------------------------------------------------------------
|
|
# These only matter to developers (testing, linting, formatting). End users
|
|
# don't install them. Activated with: `uv sync --extra dev` or `--all-extras`.
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
# pytest — runs our test suite (the test_*.py files in tests/).
|
|
"pytest>=9.0.3",
|
|
|
|
# pytest-cov — measures how much of our code the tests actually
|
|
# exercise. "Coverage" — high coverage means well-tested code.
|
|
"pytest-cov>=7.1.0",
|
|
|
|
# ruff — extremely fast linter and formatter. Catches bugs, style
|
|
# issues, dead imports. Modern replacement for flake8/black/isort.
|
|
"ruff>=0.15.12",
|
|
|
|
# mypy — static type checker. Reads our type hints and tells us if
|
|
# we passed a string where an int was expected, BEFORE running the code.
|
|
"mypy>=2.1.0",
|
|
|
|
# pylint — second linter that catches deeper logic issues ruff misses.
|
|
"pylint>=4.0.5",
|
|
|
|
# yapf — code formatter (Google's). Keeps every file looking identical.
|
|
"yapf>=0.43.0,<1.0.0",
|
|
]
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# project.urls — links shown on PyPI / package pages
|
|
# -----------------------------------------------------------------------------
|
|
[project.urls]
|
|
Homepage = "https://github.com/CarterPerez-dev/Cybersecurity-Projects"
|
|
Repository = "https://github.com/CarterPerez-dev/Cybersecurity-Projects/tree/main/PROJECTS/foundations/password-manager"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# project.scripts — command-line entry points
|
|
# -----------------------------------------------------------------------------
|
|
# These create real shell commands when the package is installed. After
|
|
# `uv sync`, the user can type `pv add github` instead of
|
|
# `python -m password_manager add github`. The right-hand side is
|
|
# "<module>:<function>" — the function gets called when the command runs.
|
|
[project.scripts]
|
|
pv = "password_manager.main:app"
|
|
password-vault = "password_manager.main:app"
|
|
|
|
|
|
# =============================================================================
|
|
# [build-system] — how to BUILD this project into an installable package
|
|
# =============================================================================
|
|
# Required by PEP 517. Tools like uv read this to know which builder
|
|
# to use. We chose hatchling — modern, fast, zero-config for our case.
|
|
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
|
|
# Tell hatchling where the actual Python code lives. Without this, it
|
|
# guesses — and guesses wrong when the layout is src/<package>/.
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["src/password_manager"]
|
|
|
|
|
|
# =============================================================================
|
|
# [tool.ruff] — linter / formatter configuration
|
|
# =============================================================================
|
|
# Ruff is the FAST one. It runs in milliseconds and catches 90% of issues.
|
|
[tool.ruff]
|
|
# Target Python version — ruff adjusts which warnings apply.
|
|
target-version = "py313"
|
|
|
|
# Wrap lines at 88 characters (PEP 8 says 79, but 88 is the modern norm).
|
|
line-length = 88
|
|
|
|
# Tell ruff "the source code lives in src/" so imports resolve correctly.
|
|
src = ["src"]
|
|
|
|
# Don't lint these directories.
|
|
exclude = [
|
|
".git",
|
|
".venv",
|
|
"__pycache__",
|
|
"venv",
|
|
"build",
|
|
"dist",
|
|
]
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Which lint rules to enable. Each "code" is a category of check.
|
|
# -----------------------------------------------------------------------------
|
|
[tool.ruff.lint]
|
|
select = [
|
|
"E", # pycodestyle errors — basic PEP 8 spacing/indent rules
|
|
"F", # Pyflakes — unused imports, undefined names, real bugs
|
|
"W", # pycodestyle warnings — softer style issues
|
|
"B", # Bugbear — sneaky bugs (mutable default args, etc.)
|
|
"C4", # Comprehensions — encourages cleaner list/dict comprehensions
|
|
"UP", # Pyupgrade — flags old syntax we should modernize
|
|
"SIM", # Simplify — suggests cleaner equivalents
|
|
]
|
|
|
|
# Some rules we deliberately ignore.
|
|
ignore = [
|
|
# Line length is handled by yapf, not ruff. Avoids double-flagging.
|
|
"E501",
|
|
]
|
|
|
|
|
|
# =============================================================================
|
|
# [tool.mypy] — static type checker configuration
|
|
# =============================================================================
|
|
# Mypy reads our type hints (the `: int`, `-> str` parts) and verifies them
|
|
# without running the code. Catches whole categories of bugs at edit time.
|
|
[tool.mypy]
|
|
python_version = "3.13"
|
|
|
|
# Treat anything returning Any as a warning — Any is a type-system escape
|
|
# hatch and we want to know when we're using it.
|
|
warn_return_any = true
|
|
|
|
# Warn if our config has unused settings (typos, etc.).
|
|
warn_unused_configs = true
|
|
|
|
# Require type annotations on every function. STRICT mode — appropriate
|
|
# for a security-critical project where bugs = leaked passwords.
|
|
disallow_untyped_defs = true
|
|
disallow_incomplete_defs = true
|
|
|
|
# Don't auto-add Optional just because a default is None. Be explicit.
|
|
no_implicit_optional = true
|
|
|
|
# Warn if we cast a value to a type it already has (dead code).
|
|
warn_redundant_casts = true
|
|
|
|
# Warn if a function might fall off the end without returning.
|
|
warn_no_return = true
|
|
|
|
# Pretty error output — helps when reading mypy output.
|
|
show_error_codes = true
|
|
show_column_numbers = true
|
|
pretty = true
|
|
|
|
exclude = [
|
|
".venv",
|
|
"venv",
|
|
"tests", # tests use fixtures and don't need strict typing
|
|
]
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Per-module overrides — silence missing stubs for argon2.
|
|
# argon2-cffi doesn't ship type hints, so mypy can't check it. That's fine.
|
|
# -----------------------------------------------------------------------------
|
|
[[tool.mypy.overrides]]
|
|
module = ["argon2.*"]
|
|
ignore_missing_imports = true
|
|
|
|
|
|
# =============================================================================
|
|
# [tool.pylint] — second-opinion linter
|
|
# =============================================================================
|
|
# Slower than ruff but catches different things — class design issues,
|
|
# dead variables, complex code patterns.
|
|
[tool.pylint.main]
|
|
py-version = "3.13"
|
|
jobs = 4 # run in parallel across 4 cores
|
|
persistent = true # cache results between runs
|
|
|
|
ignore = [
|
|
"venv",
|
|
".venv",
|
|
"__pycache__",
|
|
"build",
|
|
"dist",
|
|
".git",
|
|
"tests",
|
|
]
|
|
|
|
# Specific pylint warnings we deliberately turn off.
|
|
[tool.pylint.messages_control]
|
|
disable = [
|
|
"R0903", # too-few-public-methods — small data classes are fine
|
|
"C0103", # invalid-name — we use short names like `kdf` on purpose
|
|
"C0325", # superfluous-parens — fights with yapf formatting
|
|
]
|
|
|
|
# Override pylint's default complexity limits where they're too strict.
|
|
[tool.pylint.design]
|
|
max-args = 8 # default is 5; we sometimes need a few more
|
|
max-attributes = 10 # default is 7
|
|
|
|
# Foundation-tier modules carry heavy teaching comments and multi-
|
|
# paragraph docstrings, which push a single self-contained module
|
|
# above the default 1000-line ceiling. The right answer is not to
|
|
# split the module artificially — keeping vault.py as one place to
|
|
# read end-to-end is the pedagogical point — so we lift the cap.
|
|
[tool.pylint.format]
|
|
max-module-lines = 1500
|
|
|
|
|
|
# =============================================================================
|
|
# [tool.pytest.ini_options] — test runner configuration
|
|
# =============================================================================
|
|
[tool.pytest.ini_options]
|
|
# Where the test files live.
|
|
testpaths = ["tests"]
|
|
|
|
# Files that match this pattern are treated as test modules.
|
|
python_files = ["test_*.py"]
|
|
|
|
# Default flags every `pytest` invocation gets:
|
|
# -v → verbose, show each test name
|
|
# --tb=short → short tracebacks on failure (less wall of text)
|
|
addopts = "-v --tb=short"
|