[build-system] requires = ["setuptools>=77", "wheel"] build-backend = "setuptools.build_meta" [project] # Distribution name on PyPI is "unifioptimizer" (the product name); the import # package and the console script both stay "netadmin". Dist-name != import-name # is fully supported: pip installs "unifioptimizer", `import netadmin` works, and # the `netadmin` command is registered via [project.scripts] below. name = "unifioptimizer" version = "0.8.2" description = "The incident engine for UniFi: keeps the history your controller throws away and turns it into tracked, root-caused issues with revertible fixes." readme = "README.md" license = "MIT" license-files = ["LICENSE"] requires-python = ">=3.11" authors = [{ name = "Gary Neitzke", email = "6740929+gneitzke@users.noreply.github.com" }] keywords = [ "unifi", "ubiquiti", "network-monitoring", "wifi", "self-hosted", "sqlite", "home-assistant", "observability", "homelab", "incident-management", "root-cause-analysis", "unifi-network", ] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Environment :: Web Environment", "Framework :: FastAPI", "Intended Audience :: System Administrators", "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: System :: Networking :: Monitoring", "Topic :: System :: Systems Administration", ] dependencies = [ "httpx>=0.27", "pydantic>=2", "pydantic-settings>=2", "APScheduler>=3.10", "websockets>=12", "pyyaml>=6", "rich>=13", "fastapi>=0.104", "uvicorn[standard]>=0.24", "dnspython>=2", "aiomqtt>=2", ] [project.urls] Homepage = "https://github.com/gneitzke/UnifiOptimizer" Repository = "https://github.com/gneitzke/UnifiOptimizer" Issues = "https://github.com/gneitzke/UnifiOptimizer/issues" Documentation = "https://github.com/gneitzke/UnifiOptimizer/blob/main/docs/ARCHITECTURE.md" [project.optional-dependencies] # What the netadmin test suite actually imports/uses (matches reality; installed). test = [ "pytest>=8", "pytest-asyncio>=0.23", "respx>=0.21", "pytest-cov>=5", ] # The read-only MCP server (docs/MCP_SERVER.md). Deliberately an extra, not a core # dependency: the daemon does not need it, and the core install stays at 11 runtime # deps. `netadmin-mcp` imports the SDK lazily and prints this install line if absent. # Upper bound is load-bearing, not caution. The SDK's 2.0 removed # `mcp.shared.memory.create_connected_server_and_client_session` and changed # `Server.list_tools`, both of which this code and its tests use. While the spec # said only `>=1.2`, a fresh `pip install "unifioptimizer[mcp]"` resolved 2.0 and # produced an MCP server that could not start. Widen this only alongside the port. mcp = ["mcp>=1.2,<2"] [project.scripts] netadmin = "netadmin.cli:main" netadmin-mcp = "netadmin.mcp.server:main" # --- Packaging: ship only the netadmin package, with the prebuilt web UI as # package data so `pip install` gives a working dashboard with ZERO Node. # The bundled UI lives at netadmin/_webui/ and is produced by # `python tools/build_web.py` before the wheel is built (see # .github/workflows/release.yml). The old top-level dirs (core/, api/, # utils/, ...) are intentionally excluded from the distribution. [tool.setuptools.packages.find] include = ["netadmin*"] namespaces = false [tool.setuptools] include-package-data = true [tool.setuptools.package-data] # The prebuilt web UI (no Node needed at runtime), the numbered SQL migrations # the store applies at startup via netadmin/store/db.py:MIGRATIONS_DIR, AND the # device-capability KB located by netadmin/detect/device_kb.py — all non-.py # runtime data that must ship inside the wheel. Without the first two `netadmin` # cannot boot; without the third the known_pathology and bad-cable detectors # silently run with no device knowledge base. netadmin = ["_webui/**/*", "store/migrations/*.sql", "data/*.json"] [tool.black] line-length = 100 target-version = ['py311', 'py312'] include = '\.pyi?$' extend-exclude = ''' /( # directories \.git | __pycache__ | \.venv | venv | env | build | dist | Archive )/ ''' [tool.isort] profile = "black" line_length = 100 skip_gitignore = true extend_skip = ["Archive"] known_first_party = ["api", "core", "utils"] sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"] [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] addopts = "-v --tb=short" [tool.coverage.run] source = ["netadmin"] omit = ["*/tests/*", "*/__pycache__/*"] [tool.coverage.report] show_missing = true fail_under = 0