Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Breeze installation and reinstallation support both uv and pipx #43607

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/actions/install-pre-commit/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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.
#
---
name: 'Install pre-commit'
description: 'Installs pre-commit and related packages'
inputs:
python-version:
description: 'Python version to use'
default: 3.9
uv-version:
description: 'uv version to use'
default: 0.4.29
pre-commit-version:
description: 'pre-commit version to use'
default: 4.0.1
pre-commit-uv-version:
description: 'pre-commit-uv version to use'
default: 4.1.4
runs:
using: "composite"
steps:
- name: Install pre-commit, uv, and pre-commit-uv
shell: bash
run: >
pip install
pre-commit==${{inputs.pre-commit-version}}
uv==${{inputs.uv-version}}
pre-commit-uv==${{inputs.pre-commit-uv-version}}
- name: Cache pre-commit envs
uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: "pre-commit-${{inputs.python-version}}-${{ hashFiles('.pre-commit-config.yaml') }}"
restore-keys: |
pre-commit-${{inputs.python-version}}-
13 changes: 4 additions & 9 deletions .github/workflows/basic-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,11 @@ jobs:
- name: "Install Breeze"
uses: ./.github/actions/breeze
id: breeze
- name: Cache pre-commit envs
uses: actions/cache@v4
- name: "Install pre-commit"
uses: ./.github/actions/install-pre-commit
id: pre-commit
with:
path: ~/.cache/pre-commit
# yamllint disable-line rule:line-length
key: "pre-commit-${{steps.breeze.outputs.host-python-version}}-${{ hashFiles('.pre-commit-config.yaml') }}"
restore-keys: "\
pre-commit-${{steps.breeze.outputs.host-python-version}}-\
${{ hashFiles('.pre-commit-config.yaml') }}\n
pre-commit-${{steps.breeze.outputs.host-python-version}}-"
python-version: ${{steps.breeze.outputs.host-python-version}}
- name: Fetch incoming commit ${{ github.sha }} with its parent
uses: actions/checkout@v4
with:
Expand Down
20 changes: 10 additions & 10 deletions .github/workflows/static-checks-mypy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,11 @@ jobs:
- name: "Prepare breeze & CI image: ${{ inputs.default-python-version}}:${{ inputs.image-tag }}"
uses: ./.github/actions/prepare_breeze_and_image
id: breeze
- name: Cache pre-commit envs
uses: actions/cache@v4
- name: "Install pre-commit"
uses: ./.github/actions/install-pre-commit
id: pre-commit
with:
path: ~/.cache/pre-commit
# yamllint disable-line rule:line-length
key: "pre-commit-${{steps.breeze.outputs.host-python-version}}-${{ hashFiles('.pre-commit-config.yaml') }}"
restore-keys: |
pre-commit-${{steps.breeze.outputs.host-python-version}}-
python-version: ${{steps.breeze.outputs.host-python-version}}
- name: "Static checks"
run: breeze static-checks --all-files --show-diff-on-failure --color always --initialize-environment
env:
Expand Down Expand Up @@ -170,10 +167,13 @@ jobs:
- name: "Prepare breeze & CI image: ${{ inputs.default-python-version }}:${{ inputs.image-tag }}"
uses: ./.github/actions/prepare_breeze_and_image
id: breeze
- name: "Install pre-commit"
uses: ./.github/actions/install-pre-commit
id: pre-commit
with:
python-version: ${{steps.breeze.outputs.host-python-version}}
- name: "MyPy checks for ${{ matrix.mypy-check }}"
run: |
pip install pre-commit
pre-commit run --color always --verbose --hook-stage manual ${{matrix.mypy-check}} --all-files
run: pre-commit run --color always --verbose --hook-stage manual ${{matrix.mypy-check}} --all-files
env:
VERBOSE: "false"
COLUMNS: "250"
Expand Down
2 changes: 1 addition & 1 deletion contributing-docs/03_contributors_quick_start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ You can still add uv support for pre-commit if you use pipx using the commands:

pipx install pre-commit
pipx inject
pipx inject pre-commit pre-commit-uv
pipx inject prepare_breeze_and_image

Also, if you already use ``uvx`` instead of ``pipx``, use this command:

Expand Down
25 changes: 20 additions & 5 deletions dev/breeze/doc/01_installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,28 @@ Docker in WSL 2
If VS Code is installed on the Windows host system then in the WSL Linux Distro
you can run ``code .`` in the root directory of you Airflow repo to launch VS Code.

The pipx tool
--------------
The uv tool
-----------

We are recommending to use the ``uv`` tool to manage your virtual environments and generally as a swiss-knife
potiuk marked this conversation as resolved.
Show resolved Hide resolved
of your Python environment (it supports installing various versions of Python, creating virtual environments,
installing packages, managing workspaces and running development tools.).

Installing ``uv`` is described in the `uv documentation <https://docs.astral.sh/uv/getting-started/installation/>`_.
We highly recommend using ``uv`` to manage your Python environments, as it is very comprehensive,
easy to use, it is faster than any of the other tools availables (way faster!) and has a lot of features
that make it easier to work with Python.

Alternative: pipx tool
----------------------

We are using ``pipx`` tool to install and manage Breeze. The ``pipx`` tool is created by the creators
However, we do not want to be entirely dependent on ``uv`` as it is a software governed by a VC-backed vendor,
so we always want to provide open-source governed alternatives for our tools. If you can't or do not want to
use ``uv``, we got you covered. Another too you can use to manage development tools (and ``breeze`` development
environment is Python-Software-Foundation managed ``pipx``. The ``pipx`` tool is created by the creators
of ``pip`` from `Python Packaging Authority <https://www.pypa.io/en/latest/>`_

Note that ``pipx`` >= 1.4.1 is used.
Note that ``pipx`` >= 1.4.1 should be used.

Install pipx

Expand All @@ -172,7 +187,7 @@ environments. This can be done automatically by the following command (follow in

pipx ensurepath

In Mac
In case ``pipx`` is not in your PATH, you can run it with Python module:

.. code-block:: bash

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ def static_checks(
for attempt in range(1, 1 + max_initialization_attempts):
get_console().print(f"[info]Attempt number {attempt} to install pre-commit environments")
initialization_result = run_command(
[sys.executable, "-m", "pre_commit", "install", "--install-hooks"],
["pre-commit", "install", "--install-hooks"],
check=False,
no_output_dump_on_exception=True,
text=True,
Expand All @@ -874,7 +874,7 @@ def static_checks(
get_console().print("[error]Could not install pre-commit environments[/]")
sys.exit(return_code)

command_to_execute = [sys.executable, "-m", "pre_commit", "run"]
command_to_execute = ["pre-commit", "run"]
if not one_or_none_set([last_commit, commit_ref, only_my_changes, all_files]):
get_console().print(
"\n[error]You can only specify "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,14 @@ class VersionedFile(NamedTuple):
AIRFLOW_PIP_VERSION = "24.3.1"
AIRFLOW_UV_VERSION = "0.4.29"
AIRFLOW_USE_UV = False
WHEEL_VERSION = "0.36.2"
GITPYTHON_VERSION = "3.1.40"
RICH_VERSION = "13.7.0"
NODE_VERSION = "21.2.0"
PRE_COMMIT_VERSION = "3.5.0"
HATCH_VERSION = "1.9.1"
PYYAML_VERSION = "6.0.1"
# TODO: automate thsese as well
WHEEL_VERSION = "0.44.0"
GITPYTHON_VERSION = "3.1.43"
RICH_VERSION = "13.9.4"
NODE_VERSION = "22.2.0"
PRE_COMMIT_VERSION = "4.0.1"
HATCH_VERSION = "1.13.0"
PYYAML_VERSION = "6.0.2"

AIRFLOW_BUILD_DOCKERFILE = f"""
FROM python:{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}-slim-{ALLOWED_DEBIAN_VERSIONS[0]}
Expand Down
28 changes: 18 additions & 10 deletions dev/breeze/src/airflow_breeze/global_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@
except ImportError:
get_console().print(
"\n[error]Breeze doesn't support Python version <=3.8\n\n"
"[warning]Use Python 3.9 and force reinstall breeze with pipx\n\n"
" pipx install --force -e ./dev/breeze\n"
"[warning]Use Python 3.9 and force reinstall breeze:"
""
" either with uv: \n\n"
" uv tool install --force --reinstall --editable ./dev/breeze\n\n"
""
" or with pipx\n\n"
" pipx install --force -e ./dev/breeze --python 3.9\n"
"\nTo find out more, visit [info]https://github.com/apache/airflow/"
"blob/main/dev/breeze/doc/01_installation.rst#the-pipx-tool[/]\n"
"blob/main/dev/breeze/doc/01_installation.rst[/]\n"
)
sys.exit(1)
from pathlib import Path
Expand Down Expand Up @@ -253,13 +258,16 @@ def all_helm_test_packages() -> list[str]:

@cache
def all_task_sdk_test_packages() -> list[str]:
return sorted(
[
candidate.name
for candidate in (AIRFLOW_SOURCES_ROOT / "task_sdk" / "tests").iterdir()
if candidate.is_dir() and candidate.name != "__pycache__"
]
)
try:
return sorted(
[
candidate.name
for candidate in (AIRFLOW_SOURCES_ROOT / "task_sdk" / "tests").iterdir()
if candidate.is_dir() and candidate.name != "__pycache__"
]
)
except FileNotFoundError:
return []


ALLOWED_TASK_SDK_TEST_PACKAGES = [
Expand Down
5 changes: 1 addition & 4 deletions dev/breeze/src/airflow_breeze/utils/kubernetes_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,10 +391,7 @@ def create_virtualenv(force_venv_setup: bool) -> RunCommandResult:
"[info]You can uninstall breeze and install it again with earlier Python "
"version. For example:[/]\n"
)
get_console().print("pipx reinstall --python PYTHON_PATH apache-airflow-breeze\n")
get_console().print(
f"[info]PYTHON_PATH - path to your Python binary(< {higher_python_version_tuple})[/]\n"
)

get_console().print("[info]Then recreate your k8s virtualenv with:[/]\n")
get_console().print("breeze k8s setup-env --force-venv-setup\n")
sys.exit(1)
Expand Down
13 changes: 7 additions & 6 deletions dev/breeze/src/airflow_breeze/utils/path_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ def reinstall_if_setup_changed() -> bool:
return False
if "apache-airflow-breeze" in e.msg:
print(
"""Missing Package `apache-airflow-breeze`.
Use `pipx install -e ./dev/breeze` to install the package."""
"""Missing Package `apache-airflow-breeze`. Please install it.\n
Use `uv tool install -e ./dev/breeze or `pipx install -e ./dev/breeze`
to install the package."""
)
return False
sources_hash = get_installation_sources_config_metadata_hash()
Expand Down Expand Up @@ -224,10 +225,10 @@ def get_used_airflow_sources() -> Path:
@cache
def find_airflow_sources_root_to_operate_on() -> Path:
"""
Find the root of airflow sources we operate on. Handle the case when Breeze is installed via `pipx` from
a different source tree, so it searches upwards of the current directory to find the right root of
airflow directory we are actually in. This **might** be different than the sources of Airflow Breeze
was installed from.
Find the root of airflow sources we operate on. Handle the case when Breeze is installed via
`pipx` or `uv tool` from a different source tree, so it searches upwards of the current directory
to find the right root of airflow directory we are actually in. This **might** be different
than the sources of Airflow Breeze was installed from.

If not found, we operate on Airflow sources that we were installed it. This handles the case when
we run Breeze from a "random" directory.
Expand Down
7 changes: 4 additions & 3 deletions dev/breeze/src/airflow_breeze/utils/python_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ def check_python_version(release_provider_packages: bool = False):
get_console().print(
"[warning]Please reinstall Breeze using Python 3.9 - 3.11 environment because not all "
"provider packages support Python 3.12 yet.[/]\n\n"
"For example:\n\n"
"pipx uninstall apache-airflow-breeze\n"
"pipx install --python $(which python3.9) -e ./dev/breeze --force\n"
"If you are using uv:\n\n"
" uv tool install --force --reinstall --python 3.9 -e ./dev/breeze\n\n"
"If you are using pipx:\n\n"
" pipx install --python $(which python3.9) --force -e ./dev/breeze\n"
)
sys.exit(1)
13 changes: 11 additions & 2 deletions dev/breeze/src/airflow_breeze/utils/reinstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,24 @@

def reinstall_breeze(breeze_sources: Path, re_run: bool = True):
"""
Reinstalls Breeze from specified sources.
Re-installs Breeze from specified sources.
:param breeze_sources: Sources where to install Breeze from.
:param re_run: whether to re-run the original command that breeze was run with.
"""
# First check if `breeze` is installed with uv and if it is, reinstall it using uv
# If not - we assume pipx is used and we reinstall it using pipx
# Note that we cannot use `pipx upgrade` here because we sometimes install
# Breeze from different sources than originally installed (i.e. when we reinstall airflow
# From the current directory.
get_console().print(f"\n[info]Reinstalling Breeze from {breeze_sources}\n")
subprocess.check_call(["pipx", "install", "-e", str(breeze_sources), "--force"])
result = subprocess.run(["uv", "tool", "list"], text=True, capture_output=True, check=False)
if result.returncode == 0:
if "apache-airflow-breeze" in result.stdout:
subprocess.check_call(
["uv", "tool", "install", "--force", "--reinstall", "-e", breeze_sources.as_posix()]
)
else:
subprocess.check_call(["pipx", "install", "-e", breeze_sources.as_posix(), "--force"])
if re_run:
# Make sure we don't loop forever if the metadata hash hasn't been updated yet (else it is tricky to
# run pre-commit checks via breeze!)
Expand Down
26 changes: 18 additions & 8 deletions dev/breeze/src/airflow_breeze/utils/run_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,14 @@ def assert_pre_commit_installed():
python_executable = sys.executable
get_console().print(f"[info]Checking pre-commit installed for {python_executable}[/]")
command_result = run_command(
[python_executable, "-m", "pre_commit", "--version"],
["pre-commit", "--version"],
capture_output=True,
text=True,
check=False,
)
if command_result.returncode == 0:
if command_result.stdout:
pre_commit_version = command_result.stdout.split(" ")[-1].strip()
pre_commit_version = command_result.stdout.split(" ")[1].strip()
if Version(pre_commit_version) >= Version(min_pre_commit_version):
get_console().print(
f"\n[success]Package pre_commit is installed. "
Expand All @@ -238,6 +238,20 @@ def assert_pre_commit_installed():
f"aat least {min_pre_commit_version} and is {pre_commit_version}.[/]\n\n"
)
sys.exit(1)
if "pre-commit-uv" not in command_result.stdout:
get_console().print(
"\n[warning]You can significantly improve speed of installing your pre-commit envs "
"by installing `pre-commit-uv` with it.[/]\n"
)
get_console().print(
"\n[warning]With uv you can install it with:[/]\n\n"
" uv tool install pre-commit --with pre-commit-uv --force-reinstall\n"
)
get_console().print(
"\n[warning]With pipx you can install it with:[/]\n\n"
" pipx inject\n"
" pipx inject pre-commit pre-commit-uv\n"
)
else:
get_console().print(
"\n[warning]Could not determine version of pre-commit. You might need to update it![/]\n"
Expand Down Expand Up @@ -459,9 +473,7 @@ def run_compile_www_assets(
"[info]However, it requires you to have local yarn installation.\n"
)
command_to_execute = [
sys.executable,
"-m",
"pre_commit",
"pre-commit",
"run",
"--hook-stage",
"manual",
Expand Down Expand Up @@ -512,9 +524,7 @@ def run_compile_ui_assets(
"[info]However, it requires you to have local pnpm installation.\n"
)
command_to_execute = [
sys.executable,
"-m",
"pre_commit",
"pre-commit",
"run",
"--hook-stage",
"manual",
Expand Down
7 changes: 5 additions & 2 deletions scripts/ci/pre_commit/common_precommit_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,11 @@ def initialize_breeze_precommit(name: str, file: str):
if shutil.which("breeze") is None:
console.print(
"[red]The `breeze` command is not on path.[/]\n\n"
"[yellow]Please install breeze with `pipx install -e ./dev/breeze` from Airflow sources "
"and make sure you run `pipx ensurepath`[/]\n\n"
"[yellow]Please install breeze.\n"
"You can use uv with `uv tool install -e ./dev/breeze or "
"`pipx install -e ./dev/breeze`.\n"
"It will install breeze from Airflow sources "
"(make sure you run `pipx ensurepath` if you use pipx)[/]\n\n"
"[bright_blue]You can also set SKIP_BREEZE_PRE_COMMITS env variable to non-empty "
"value to skip all breeze tests."
)
Expand Down