blob: febea0abab3dcd373418d2d94d5df0af1defcd65 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
[project]
name = "apache-airflow-ctl"
dynamic = ["version"]
description = "Apache Airflow command line tool for communicating with an Apache Airflow, using the API."
readme = { file = "README.md", content-type = "text/markdown" }
license = "Apache-2.0"
license-files = ["LICENSE", "NOTICE"]
# We do not want to upper-bind Python version unnecessarily. Airflow-ctl is a small tool with
# minimal dependencies and does not use sophisticated Python features, so it should work with
# new Python versions once all dependencies are updated to support them.
requires-python = ">=3.10,!=3.15"
dependencies = [
# TODO there could be still missing deps such as airflow-core
"argcomplete>=1.10",
# Remove the <1.0 cap after migrating to httpx 1.x (ground-up API rewrite — no HTTPStatusError etc.);
# tracked at https://github.com/apache/airflow/issues/65609
"httpx>=0.27.0,<1.0",
"keyring>=25.7.0",
"lazy-object-proxy>=1.2.0",
"methodtools>=0.4.7",
"platformdirs>=4.3.6",
"pydantic>=2.11.0", # https://github.com/apache/airflow/issues/56482
"pyyaml>=6.0.3",
"rich-argparse>=1.0.0",
"structlog>=26.1.0",
"uuid6>=2024.7.10",
"tabulate>=0.9.0",
"tenacity>=9.1.4",
]
classifiers = [
"Framework :: Apache Airflow",
]
[project.urls]
"Bug Tracker" = "https://github.com/apache/airflow/issues"
Documentation = "https://airflow.apache.org/docs/apache-airflow-ctl/stable/index.html"
Downloads = "https://archive.apache.org/dist/airflow/airflow-ctl/"
Homepage = "https://airflow.apache.org/"
"Release Notes" = "https://airflow.apache.org/docs/apache-airflow-ctl/stable/changelog.html"
"Slack Chat" = "https://s.apache.org/airflow-slack"
"Source Code" = "https://github.com/apache/airflow"
LinkedIn = "https://www.linkedin.com/company/apache-airflow/"
Mastodon = "https://fosstodon.org/@airflow"
Bluesky = "https://bsky.app/profile/apache-airflow.bsky.social"
YouTube = "https://www.youtube.com/channel/UCSXwxpWZQ7XZ1WL3wqevChA/"
[project.optional-dependencies]
"dev" = [
"keyrings.alt>=5.0.2",
]
[project.scripts]
airflowctl = "airflowctl.__main__:main"
# Redundant definition allowing direct execution via `uvx apache-airflow-ctl ...`
apache-airflow-ctl = "airflowctl.__main__:main"
[build-system]
requires = [
"hatchling==1.32.4",
"packaging==26.3",
"pathspec==1.1.1",
"pluggy==1.6.0",
"tomli==2.4.1; python_version < '3.11'",
"tomlkit==0.15.1",
"trove-classifiers==2026.9.21.13",
]
build-backend = "hatchling.build"
[tool.hatch.version]
path = "src/airflowctl/__init__.py"
[tool.hatch.build.targets.wheel]
packages = ["src/airflowctl"]
[tool.ruff]
extend = "../pyproject.toml"
src = ["src"]
namespace-packages = ["src/airflowctl"]
[tool.ruff.lint.per-file-ignores]
# Ignore Doc rules et al for anything outside of tests
"!src/*" = ["D", "TID253", "S101", "TRY002"]
# Ignore the pytest rules outside the tests folder - https://github.com/astral-sh/ruff/issues/14205
"!tests/*" = ["PT"]
# Pycharm barfs if this "stub" file has future imports
"src/airflowctl/__init__.py" = ["I002"]
# Generated file, be less strict
"src/airflowctl/api/datamodels/generated.py" = ["UP007", "D101", "D200"]
"src/airflowctl/api/datamodels/auth_generated.py" = ["UP007", "D101", "D200"]
[tool.coverage.run]
branch = true
relative_files = true
source = ["src/airflowctl"]
include_namespace_packages = true
[tool.coverage.report]
skip_empty = true
exclude_also = [
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"@(abc\\.)?abstractmethod",
"@(typing(_extensions)?\\.)?overload",
"if (typing(_extensions)?\\.)?TYPE_CHECKING:",
]
[dependency-groups]
# To build docs:
#
# uv run --group docs build-docs
#
# To enable auto-refreshing build with server:
#
# uv run --group docs build-docs --autobuild
#
# To see more options:
#
# uv run --group docs build-docs --help
#
docs = [
"apache-airflow-devel-common[docs]"
]
dev = [
"apache-airflow-ctl[dev]",
"apache-airflow-devel-common",
]
codegen = [
"datamodel-code-generator[http]>=0.71.0",
"apache-airflow-devel-common"
]
# uv run --verbose --group codegen --project apache-airflow-ctl --directory airflow-ctl/ datamodel-codegen --url="http://0.0.0.0:28080/auth/openapi.json" --output=src/airflowctl/api/datamodels/auth_generated.py
mypy = [
"apache-airflow-devel-common[mypy]",
]
[tool.datamodel-codegen]
capitalise-enum-members=true # `State.RUNNING` not `State.running`
disable-timestamp=true
enable-version-header=true
enum-field-as-literal='one' # When a single enum member, make it output a `Literal["..."]`
input-file-type='openapi'
output-model-type='pydantic_v2.BaseModel'
output-datetime-class='datetime'
target-python-version='3.10'
use-annotated=true
use-default=true
use-double-quotes=true
use-schema-description=true # Desc becomes class doc comment
use-standard-collections=true # list[] not List[]
use-subclass-enum=true # enum, not union of Literals
use-union-operator=true # +annotations, not `Union[]`
input = "../airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml"
output = "src/airflowctl/api/datamodels/generated.py"
## pytest settings ##
[tool.pytest]
addopts = [
"--tb=short",
"-rasl",
"--verbosity=2",
# Disable `flaky` plugin for pytest. This plugin conflicts with `rerunfailures` because provide the same marker.
"-p", "no:flaky",
# Disable `nose` builtin plugin for pytest. This feature is deprecated in 7.2 and will be removed in pytest>=8
"-p", "no:nose",
# Disable support of a legacy `LocalPath` in favor of stdlib `pathlib.Path`.
"-p", "no:legacypath",
# Disable warnings summary, because we use our warning summary.
"--disable-warnings",
"--asyncio-mode=strict",
]
markers = [
"flaky(reruns, reruns_delay): retry test on failure using pytest-rerunfailures"
]
norecursedirs = [
".eggs",
]
log_level = "INFO"
filterwarnings = [
"error::pytest.PytestCollectionWarning",
]
python_files = [
"test_*.py",
]
testpaths = [
"tests",
]
asyncio_default_fixture_loop_scope = "function"
pythonpath = ["tests"]
# Keep temporary directories (created by `tmp_path`) for 2 recent runs only failed tests.
tmp_path_retention_count = "2"
tmp_path_retention_policy = "failed"
[tool.uv]
required-version = ">=0.11.8"
[tool.uv.sources]
apache-airflow-devel-common = { workspace = true }