pyproject.toml (481 lines of code) (raw):

#################### # Project Metadata # #################### [project] description = "Database Migration Assessment" license = { text = "Apache-2.0" } name = "dma" readme = "README.md" requires-python = ">=3.9" version = "4.3.44" # keywords for easier look-up on PyPI authors = [ { name = "Cody Fincher", email = "codyfincher@google.com" }, { name = "Warren Puziewicz", email = "wpuziewicz@google.com" }, { name = "Steve Senior", email = "stevesenior@google.com" }, { name = "Shane Borden", email = "shaneborden@google.com" }, { name = "Eri Santos", email = "erisantos@google.com" }, ] keywords = [ "database", "migration", "assessment", "postgres", "mysql", "oracle", "mssql", "duckdb", "litestar", "dma", "granian", "gcp", "google", "alloydb", "mariadb", ] maintainers = [ { name = "Cody Fincher", email = "codyfincher@google.com" }, { name = "Warren Puziewicz", email = "wpuziewicz@google.com" }, { name = "Steve Senior", email = "stevesenior@google.com" }, { name = "Shane Borden", email = "shaneborden@google.com" }, ] # options under https://pypi.org/classifiers/ classifiers = [ # ToDo: Modify according to your needs! "Development Status :: 2 - Pre-Alpha", "Programming Language :: Python", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", ] # direct dependencies of this package, installed when users `pip install dma` later. dependencies = [ "duckdb>=1.0.0", "polars[pyarrow]>=0.20.0", "aiosql>=9.4", "click>=8.1.7", "rich-click>=1.7.3", "jinja2>=3.1.3", "sqlalchemy>=2.0.25", "typing-extensions>=4.0.0", "msgspec", "greenlet", "anyio" ] [project.urls] # important URLs for this project Documentation = "https://googlecloudplatform.github.io/database-assessment/" Issues = "https://github.com/GoogleCloudPlatform/database-assessment/issues" Source = "https://github.com/GoogleCloudPlatform/database-assessment" [project.optional-dependencies] mssql = ["aioodbc"] mysql = ["asyncmy>=0.2.9"] oracle = ["oracledb"] postgres = ["psycopg[pool,binary]"] server = ["litestar[structlog,jinja]>=2.7.0", "litestar-granian>=0.2.3"] [project.scripts] dma = "dma.cli.main:app" ###################### # Build & Versioning # ###################### [build-system] build-backend = "hatchling.build" requires = ["hatchling"] [tool.hatch.metadata] # direct dependency references, e.g `pip @ git+https://github.com/pypa/pip.git@master` allow-direct-references = true [tool.hatch.build] dev-mode-dirs = ["src/"] sources = ["src"] [tool.hatch.build.targets.sdist] exclude = ["/.github", "/docs"] # [tool.hatch.build.targets.app] # python = "3.12" ##################### # Environment Setup # ##################### # Default environment with production dependencies [tool.hatch.envs.default] extra-dependencies = [ "bump2version", "nodeenv", # required test dependencies "psycopg[binary]", "pymysql", "pymssql", "oracledb", "cython", "anyio", "coverage[toml]>=6.2", "pytest", "pytest-cov", "pytest-mock", "pytest-sugar", "pytest-click", "pytest-xdist", "pytest-databases<=0.10.0", # lint "mypy", "ruff<0.10.0", "pylint", "pre-commit", "types-click", "types-six", "types-decorator", "types-pyyaml", "types-setuptools", "asyncpg-stubs", "pyyaml>=6", # docs "mkdocs-include-markdown-plugin", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-section-index", "mkdocstrings[python]", "mkdocs-glightbox>=0.3.0", "mkdocs-material[git,imaging,recommended]", "mkdocs-minify-plugin", "mike>=2.0.0", # Extensions "pymdown-extensions>=10.5", # Necessary for syntax highlighting in code blocks "pygments>=2.13", # Validation "linkchecker>=10.3", # cli database browser "harlequin", ] installer = "uv" [tool.hatch.envs.default.scripts] upgrade-all = "PIP_COMPILE_UPGRADE=1 hatch env run --env {env_name} -- python --version" upgrade-pkg = "PIP_COMPILE_UPGRADE='{args}' hatch env run --env {env_name} -- python --version" # Test environment with test-only dependencies [tool.hatch.envs.test] features = ["server", "oracle", "mysql", "mssql", "postgres"] template = "default" type = "virtual" # Test matrix for various Python versions replacing the functionality of tox [[tool.hatch.envs.test.matrix]] python = ["3.9", "3.10", "3.11", "3.12", "3.13"] [tool.hatch.envs.test.scripts] cov = "pytest --cov-report=term-missing --cov=src/dma --cov=tests {args}" debug = "cov --no-cov -s --pdb --pdbcls=IPython.core.debugger:Pdb {args}" no-cov = "cov --no-cov {args}" # Docs environment [tool.hatch.envs.docs] features = ["server", "oracle", "mysql", "mssql", "postgres"] template = "default" type = "virtual" [tool.hatch.envs.docs.env-vars] MKDOCS_CONFIG = "mkdocs.yml" PYTHONUNBUFFERED = "1" SOURCE_DATE_EPOCH = "1580601600" [tool.hatch.envs.docs.scripts] build = "mkdocs build --config-file {env:MKDOCS_CONFIG} --clean --strict {args}" ci-build = "mike deploy --config-file {env:MKDOCS_CONFIG} --update-aliases {args}" serve = "mkdocs serve --config-file {env:MKDOCS_CONFIG} --dev-addr localhost:8000 {args}" # --ignore-url=None since the SUMMARY.md file leaves a <toc>None</toc> in sitemap.xml validate = "linkchecker --config .linkcheckerrc --ignore-url=/reference --ignore-url=None site" # https://github.com/linkchecker/linkchecker/issues/678 build-check = ["build", "validate"] [tool.hatch.envs.local] features = ["server", "oracle", "mysql", "mssql", "postgres"] lock-filename = "requirements/requirements-dev.txt" path = ".venv/" python = "3.12" template = "default" type = "virtual" [tool.hatch.envs.local.scripts] start-infra = "docker-compose -f tests/docker-compose.yml up --force-recreate -d" stop-infra = "docker-compose -f tests/docker-compose.yml down --remove-orphans --volumes" # Lint environment [tool.hatch.envs.lint] features = ["server", "oracle", "mysql", "mssql", "postgres"] python = "3.9" template = "default" type = "virtual" [tool.hatch.envs.lint.scripts] check = ["style", "typing"] fix = [ "ruff format {args:.}", "ruff check --fix --unsafe-fixes {args:.}", "typing", "style", # feedback on what is not fixable ] style = ["echo \"VERSION: `ruff --version`\"", "ruff check {args:.}", "ruff format --check {args:.}"] typing = ["echo \"VERSION: `mypy --version`\"", "mypy --install-types --non-interactive {args}"] ################## # External Tools # ################## ## Linting Tools [tool.slotscheck] strict-imports = false [tool.codespell] ignore-words-list = "alog" skip = 'pdm.lock, package-lock.json' [tool.pyright] autoSearchPaths = false exclude = ["docs/**/*.py", "tests/**/*.py", "scripts/**/*.py"] extraPaths = [] # Include paths from PYTHONPATH env var and .env definition include = ["src/dma", "tests"] pythonVersion = "3.9" reportMissingImports = "information" reportMissingTypeStubs = "information" reportUnknownMemberType = "none" reportUnnecessaryTypeIgnoreComments = true root = ['src'] typeCheckingMode = "standard" useLibraryCodeForTypes = true [tool.mypy] disallow_untyped_defs = false files = ["src/dma", "tests"] follow_imports = "normal" # "silent" for not following ignore_missing_imports = true pretty = true show_column_numbers = true warn_no_return = false warn_unused_ignores = true [[tool.mypy.overrides]] disallow_untyped_decorators = false module = ["tests.*"] warn_unused_ignores = false [[tool.mypy.overrides]] disable_error_code = ["arg-type"] disallow_untyped_calls = false disallow_untyped_decorators = false module = ["aisoql.*"] [[tool.mypy.overrides]] disallow_untyped_calls = false disallow_untyped_defs = false module = ["dma.lib.db.adapters.*", "dma.lib.db.adapters", "dma.lib.db.base", "dma.lib.db"] warn_unused_ignores = false [[tool.mypy.overrides]] ignore_missing_imports = true module = ["sqlalchemy.*", "nodeenv"] [tool.ruff] exclude = [ ".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv", '__pycache__', ] fix = true include = ["src/**/*.py", "src/**/*.pyi", "tests/**/*.py", "tests/**/*.pyi"] line-length = 120 lint.fixable = ["ALL"] lint.ignore = [ "B027", # Allow non-abstract empty methods in abstract base classes "FBT003", # Allow boolean positional values in function calls, like `dict.get(... True)` # Ignore checks for possible passwords "S105", "S106", "S107", # Ignore complexity "C901", "PLR0911", "PLR0912", "PLR0913", "PLR0915", "PLC1901", # empty string comparisons "PLW2901", # `for` loop variable overwritten "SIM114", # Combine `if` branches using logical `or` operator "E203", # Whitespace before :, needed for black compatability and also `ruff format` "ISC001", # causes unexpected behaviour with formatter "E501", # pycodestyle line too long, handled by black "D100", # pydocstyle - missing docstring in public module "D101", # pydocstyle - missing docstring in public class "D102", # pydocstyle - missing docstring in public method "D103", # pydocstyle - missing docstring in public function "D104", # pydocstyle - missing docstring in public package "D105", # pydocstyle - missing docstring in magic method "D106", # pydocstyle - missing docstring in public nested class "D107", # pydocstyle - missing docstring in __init__ "D202", # pydocstyle - no blank lines allowed after function docstring "D205", # pydocstyle - 1 blank line required between summary line and description "D415", # pydocstyle - first line should end with a period, question mark, or exclamation point "UP037", # pyupgrade - removes quotes from type annotation "A003", # flake8-builtins - class attribute {name} is shadowing a python builtin "B010", # flake8-bugbear - do not call setattr with a constant attribute value "B008", # flake8-bugbear - Do not perform function call `Parameter` in argument defaultsRuff(B008) "RUF012", # ruff - mutable class attributes should be annotated with `typing.ClassVar` "ANN401", # ruff - Dynamically typed expressions (typing.Any) are disallowed "PLR0913", # ruff - Too many arguments to function call "PLR2004", # Magic value used in comparison "FBT001", # Boolean typed positional argument in function definition "FBT002", # Boolean default positional argument in function definition "FBT003", # Boolean Boolean default positional argument in function definition "ARG002", # Unused method argument "ARG001", # Unused function argument "TD002", "TD003", "FIX002", "PGH003", "RUF006", "SLF001", "PT007", 'S603', "E501", # pycodestyle line too long, handled by black "PLW2901", # pylint - for loop variable overwritten by assignment target "ANN401", "FBT", "PLR0913", # too many arguments "PT", "TD", "PERF203", # ignore for now; investigate "COM812", "PLR0917", "DOC201", # `return` is not documented in docstring "DOC501", # Raised exception missing from docstring "DOC502", # Raised exception missing from docstring "A005", # module shadows builtin "DOC402", # Yield missing from docstring ] lint.select = ["ALL"] # Allow unused variables when underscore-prefixed. lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" preview = true # preview features & checks, use with caution src = ["src", "tests/", "scripts/", "docs/", "notebooks/"] target-version = "py39" [tool.ruff.lint.pydocstyle] convention = "google" [tool.ruff.lint.isort] known-first-party = ["dma", "tests", "scripts"] [tool.ruff.lint.flake8-tidy-imports] ban-relative-imports = "all" [tool.ruff.lint.per-file-ignores] # Allow print/pprint "docs/*" = ["S404", "INP001"] "examples/*" = ["T201"] # Tests can use magic values, assertions, and relative imports "__init__.py" = ['F401', 'D104'] "__main__.py" = ["E402"] "scripts/*.py" = ["INP001", "S404"] "scripts/masker/dma-collection-masker" = [ "PYI024", "FA100", "S202", "S311", "UP006", "UP035", "FA102", "EM101", "TRY003", "PLR6301", ] "scripts/post_build.py" = ["ERA001"] "scripts/pre_build.py" = ["ERA001"] "tests/**/*" = [ "PLR2004", "S101", "TID252", "ERA001", "ANN201", "ANN001", "D103", "D104", "T201", "S404", "PLR6301", "PLC2701", "FA102", ] # temp "src/dma/lib/db/adapters/*.py" = ["ANN001", "ANN201", "ANN204", "PLR6301"] # copyright "**/*.py" = ["CPY001", 'RUF029'] [tool.ruff.lint.mccabe] max-complexity = 12 [tool.ruff.lint.pep8-naming] classmethod-decorators = [ "classmethod", "sqlalchemy.ext.declarative.declared_attr", "sqlalchemy.orm.declared_attr.directive", "sqlalchemy.orm.declared_attr", ] # configure in-case someone runs this [tool.black] exclude = ''' /( \.git | \.mypy_cache | \.tox | venv | \.venv | _build | buck-out | build | dist )/ ''' include = '\.pyi?$' line-length = 120 ## Testing Tools [tool.pytest.ini_options] addopts = "-n 2 --dist=loadgroup -ra -q --doctest-glob='*.md'" filterwarnings = [ "ignore::DeprecationWarning:aiosql.*", "ignore::DeprecationWarning:pkg_resources", "ignore::DeprecationWarning:xdist.*", ] markers = [ "integration: Integration Tests", "unit: Unit Tests", "mysql: MySQL Tests", "postgres: Postgres Tests", "oracle: Oracle Tests", "spanner: Google Cloud Spanner Tests", "duckdb: DuckDB Tests", "mssql: Microsoft SQL Server Tests", "server: Web server and API Tests", ] minversion = "6.0" testpaths = ["tests"] [tool.coverage.run] branch = true concurrency = ["multiprocessing"] omit = [ "_version.py", # automatically created by hatch-vcs, not in repo "src/dma/__about__.py", "tests/*", "scripts/*", ] parallel = true source = ["src/dma"] [tool.coverage.paths] source = ["src/", "*/site-packages/"] [tool.coverage.report] # Regexes for lines to exclude from consideration exclude_lines = [ # Have to re-enable the standard pragma "pragma: no cover", # Don't complain about missing debug-only code: "def __repr__", "if self\\.debug", # Don't complain if tests don't hit defensive assertion code: "raise AssertionError", "raise NotImplementedError", # Don't complain if non-runnable code isn't run: "if 0:", "if __name__ == .__main__.:", "if TYPE_CHECKING:", 'class .*\bProtocol\):', '@(abc\.)?abstractmethod', ]