From 9b287dc51ac8d7081cd54312bdbc390753f180e7 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 23 Jun 2025 16:59:50 +0700 Subject: [PATCH] Python dependency/wheel tweaks - Use --locked to assert that the lockfile won't change, so we need to explicitly 'uv lock' when making changes. Still trying to get to the bottom of why the lockfile sometimes has editable entries, which break things when switching between platforms. - Exclude __pycache__ from wheels - Move the typing stubs to our dev deps (https://github.com/ankitects/anki/pull/4074#pullrequestreview-2948088436) --- CLAUDE.md | 2 +- build/configure/src/aqt.rs | 7 +++++- build/configure/src/pylib.rs | 3 ++- build/runner/src/pyenv.rs | 2 +- pylib/hatch_build.py | 10 ++++++++- pylib/pyproject.toml | 4 +--- pyproject.toml | 10 +++++++++ qt/hatch_build.py | 9 ++++++-- qt/pyproject.toml | 7 ------ uv.lock | 42 ++++++++++++++++++------------------ 10 files changed, 58 insertions(+), 38 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 6ec6db642..3be5cc70b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,7 +21,7 @@ Please do this as a final step before marking a task as completed. During development, you can build/check subsections of our code: - Rust: 'cargo check' -- Python: './tools/dmypy' +- Python: './tools/dmypy', and if wheel-related, './ninja wheels' - TypeScript/Svelte: './ninja check:svelte' Be mindful that some changes (such as modifications to .proto files) may diff --git a/build/configure/src/aqt.rs b/build/configure/src/aqt.rs index 0a9b32270..83be77e91 100644 --- a/build/configure/src/aqt.rs +++ b/build/configure/src/aqt.rs @@ -342,7 +342,12 @@ fn build_wheel(build: &mut Build) -> Result<()> { name: "aqt", version: anki_version(), platform: None, - deps: inputs![":qt:aqt", glob!("qt/aqt/**"), "qt/pyproject.toml"], + deps: inputs![ + ":qt:aqt", + glob!("qt/aqt/**"), + "qt/pyproject.toml", + "qt/hatch_build.py" + ], }, ) } diff --git a/build/configure/src/pylib.rs b/build/configure/src/pylib.rs index bcef1ecc4..21820ae8b 100644 --- a/build/configure/src/pylib.rs +++ b/build/configure/src/pylib.rs @@ -68,7 +68,8 @@ pub fn build_pylib(build: &mut Build) -> Result<()> { deps: inputs![ ":pylib:anki", glob!("pylib/anki/**"), - "pylib/pyproject.toml" + "pylib/pyproject.toml", + "pylib/hatch_build.py" ], }, )?; diff --git a/build/runner/src/pyenv.rs b/build/runner/src/pyenv.rs index 0bd5ec662..d64c8fb3f 100644 --- a/build/runner/src/pyenv.rs +++ b/build/runner/src/pyenv.rs @@ -35,7 +35,7 @@ pub fn setup_pyenv(args: PyenvArgs) { run_command( Command::new(args.uv_bin) .env("UV_PROJECT_ENVIRONMENT", args.pyenv_folder.clone()) - .args(["sync", "--frozen"]) + .args(["sync", "--locked"]) .args(args.extra_args), ); diff --git a/pylib/hatch_build.py b/pylib/hatch_build.py index c3539da56..9e8ee9799 100644 --- a/pylib/hatch_build.py +++ b/pylib/hatch_build.py @@ -35,8 +35,16 @@ class CustomBuildHook(BuildHookInterface): assert generated_root.exists(), "you should build with --wheel" for path in generated_root.rglob("*"): - if path.is_file(): + if path.is_file() and not self._should_exclude(path): relative_path = path.relative_to(generated_root) # Place files under anki/ in the distribution dist_path = "anki" / relative_path force_include[str(path)] = str(dist_path) + + def _should_exclude(self, path: Path) -> bool: + """Check if a file should be excluded from the wheel.""" + # Exclude __pycache__ + path_str = str(path) + if "/__pycache__/" in path_str: + return True + return False diff --git a/pylib/pyproject.toml b/pylib/pyproject.toml index 555f30c86..d6d41f970 100644 --- a/pylib/pyproject.toml +++ b/pylib/pyproject.toml @@ -10,10 +10,8 @@ dependencies = [ "orjson", "protobuf>=4.21", "requests[socks]", + # remove after we update to min python 3.11+ "typing_extensions", - "types-protobuf", - "types-requests", - "types-orjson", # platform-specific dependencies "distro; sys_platform != 'darwin' and sys_platform != 'win32'", "psutil; sys_platform == 'win32'", diff --git a/pyproject.toml b/pyproject.toml index f5443e229..2e47ee2f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,16 @@ dev = [ "colorama", # for isort --color "wheel", "hatchling", # for type checking hatch_build.py files + "mock", + "types-protobuf", + "types-requests", + "types-orjson", + "types-decorator", + "types-flask", + "types-flask-cors", + "types-markdown", + "types-waitress", + "types-pywin32", ] [project.optional-dependencies] diff --git a/qt/hatch_build.py b/qt/hatch_build.py index fc716a57f..aaf345842 100644 --- a/qt/hatch_build.py +++ b/qt/hatch_build.py @@ -67,11 +67,16 @@ class CustomBuildHook(BuildHookInterface): def _should_exclude(self, path: Path) -> bool: """Check if a file should be excluded from the wheel.""" - # Match the exclusions from write_wheel.py exclude_aqt function + path_str = str(path) + + # Exclude __pycache__ + if "/__pycache__/" in path_str: + return True + if path.suffix in [".ui", ".scss", ".map", ".ts"]: return True if path.name.startswith("tsconfig"): return True - if "/aqt/data" in str(path): + if "/aqt/data" in path_str: return True return False diff --git a/qt/pyproject.toml b/qt/pyproject.toml index e6537c76c..ab5f50263 100644 --- a/qt/pyproject.toml +++ b/qt/pyproject.toml @@ -15,13 +15,6 @@ dependencies = [ "pywin32; sys.platform == 'win32'", "anki-mac-helper; sys.platform == 'darwin'", "pip-system-certs!=5.1", - "mock", - "types-decorator", - "types-flask", - "types-flask-cors", - "types-markdown", - "types-waitress", - "types-pywin32", "pyqt6>=6.2", "pyqt6-webengine>=6.2", # anki dependency is added dynamically in hatch_build.py with exact version diff --git a/uv.lock b/uv.lock index 348d14dd0..ce2f9536d 100644 --- a/uv.lock +++ b/uv.lock @@ -59,9 +59,6 @@ dependencies = [ { name = "protobuf" }, { name = "psutil", marker = "sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" }, { name = "requests", extra = ["socks"] }, - { name = "types-orjson" }, - { name = "types-protobuf" }, - { name = "types-requests" }, { name = "typing-extensions" }, ] @@ -75,9 +72,6 @@ requires-dist = [ { name = "protobuf", specifier = ">=4.21" }, { name = "psutil", marker = "sys_platform == 'win32'" }, { name = "requests", extras = ["socks"] }, - { name = "types-orjson" }, - { name = "types-protobuf" }, - { name = "types-requests" }, { name = "typing-extensions" }, ] @@ -111,11 +105,21 @@ dev = [ { name = "colorama" }, { name = "hatchling" }, { name = "isort" }, + { name = "mock" }, { name = "mypy" }, { name = "mypy-protobuf" }, { name = "pychromedevtools" }, { name = "pylint" }, { name = "pytest" }, + { name = "types-decorator" }, + { name = "types-flask" }, + { name = "types-flask-cors" }, + { name = "types-markdown" }, + { name = "types-orjson" }, + { name = "types-protobuf" }, + { name = "types-pywin32" }, + { name = "types-requests" }, + { name = "types-waitress" }, { name = "wheel" }, ] @@ -133,11 +137,21 @@ dev = [ { name = "colorama" }, { name = "hatchling" }, { name = "isort" }, + { name = "mock" }, { name = "mypy" }, { name = "mypy-protobuf" }, { name = "pychromedevtools" }, { name = "pylint" }, { name = "pytest" }, + { name = "types-decorator" }, + { name = "types-flask" }, + { name = "types-flask-cors" }, + { name = "types-markdown" }, + { name = "types-orjson" }, + { name = "types-protobuf" }, + { name = "types-pywin32" }, + { name = "types-requests" }, + { name = "types-waitress" }, { name = "wheel" }, ] @@ -158,7 +172,6 @@ dependencies = [ { name = "flask" }, { name = "flask-cors" }, { name = "jsonschema" }, - { name = "mock" }, { name = "pip-system-certs", version = "4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" }, { name = "pip-system-certs", version = "5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" }, { name = "psutil", marker = "sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" }, @@ -173,12 +186,6 @@ dependencies = [ { name = "pywin32", marker = "sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" }, { name = "requests" }, { name = "send2trash" }, - { name = "types-decorator" }, - { name = "types-flask" }, - { name = "types-flask-cors" }, - { name = "types-markdown" }, - { name = "types-pywin32" }, - { name = "types-waitress" }, { name = "waitress" }, ] @@ -223,7 +230,6 @@ requires-dist = [ { name = "flask" }, { name = "flask-cors" }, { name = "jsonschema" }, - { name = "mock" }, { name = "pip-system-certs", specifier = "!=5.1" }, { name = "psutil", marker = "sys_platform == 'win32'" }, { name = "pyqt6", specifier = ">=6.2" }, @@ -251,12 +257,6 @@ requires-dist = [ { name = "pywin32", marker = "sys_platform == 'win32'" }, { name = "requests" }, { name = "send2trash" }, - { name = "types-decorator" }, - { name = "types-flask" }, - { name = "types-flask-cors" }, - { name = "types-markdown" }, - { name = "types-pywin32" }, - { name = "types-waitress" }, { name = "waitress", specifier = ">=2.0.0" }, ] provides-extras = ["audio", "qt", "qt66", "qt67", "qt69"] @@ -595,7 +595,7 @@ name = "importlib-metadata" version = "8.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp" }, + { name = "zipp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } wheels = [