Skip to content

Commit eb36dac

Browse files
authored
Merge branch 'main' into u/vineetgarg/block_activations
2 parents a4ec0d6 + 9cec497 commit eb36dac

20 files changed

Lines changed: 1756 additions & 128 deletions

File tree

.github/workflows/release.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,20 @@ jobs:
5252
# The published version comes from src/coreai_opt/_about.py, not the tag.
5353
# Fail early if they disagree so we never publish a mismatched/duplicate
5454
# version (PyPI uploads are immutable and cannot be overwritten).
55+
# `print_version.py --release` computes the version exactly as the
56+
# `make build` step below does, so this guard can't drift from what
57+
# actually gets published.
5558
# Skipped on manual dry runs, where the ref is a branch, not a vX.Y.Z tag.
59+
# Run via uv (installed above) so the interpreter satisfies
60+
# requires-python whatever the runner image ships; see the Makefile's
61+
# `version` target.
5662
if: github.event_name == 'push'
5763
run: |
5864
tag="${GITHUB_REF_NAME}"
59-
version="$(python3 -c "import runpy; print(runpy.run_path('src/coreai_opt/_about.py')['__version__'])")"
65+
version="$(uv run --no-config --no-project --python '>=3.11' scripts/make/print_version.py --release)"
6066
echo "tag=${tag} package version=${version}"
6167
if [ "${tag}" != "v${version}" ]; then
62-
echo "::error::Tag ${tag} does not match package version v${version} (src/coreai_opt/_about.py). Bump __version__ to match the release tag."
68+
echo "::error::Tag ${tag} does not match package version v${version} (src/coreai_opt/_about.py). Update latest_released_version so the release it implies matches the tag."
6369
exit 1
6470
fi
6571
- name: Build wheel and sdist

.pre-commit-config.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ repos:
319319
types: [python]
320320
exclude: ^tests/
321321

322+
- repo: local
323+
hooks:
324+
- id: check-about-version
325+
name: Check _about.py version fields
326+
description: |
327+
Check that _about.py's latest_released_version matches the repo's
328+
latest release tag, and that __version__ is its last number plus
329+
one, plus .dev0. Catches a release candidate that looks like a
330+
release has already shipped when it hasn't.
331+
entry: python scripts/pre_commit/check_about_version.py
332+
language: system
333+
files: (^|/)_about\.py$
334+
pass_filenames: false
335+
322336
- repo: local
323337
hooks:
324338
- id: towncrier-check

Makefile

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,25 @@ SHELL_RC ?=
9595
# internal-only venv defaults.
9696
ENV_ALL_EXTRAS ?= true
9797

98+
# Extra `uv pip install` arguments, applied to a venv after it is synced and to
99+
# each nox session venv (see ci/nox/noxfile.py). Use it to swap a dependency
100+
# version for one run without editing pyproject.toml or the lockfile — for
101+
# example a scheduled job testing against newer upstream builds. Empty (the
102+
# default) changes nothing.
103+
POST_INSTALL_PIP_ARGS ?=
104+
export POST_INSTALL_PIP_ARGS
105+
106+
# Re-apply POST_INSTALL_PIP_ARGS to the venv at $(1).
107+
#
108+
# setup_env.sh already does this, so only use it when a recipe installs more
109+
# packages afterwards that could pull the old version back in (see env-all).
110+
# Expands to `true` when unset. The empty check uses `$(if ...)` instead of a
111+
# shell `[ -n "..." ]` test because the args contain their own quotes.
112+
# Usage: $(call post_install_pip,VENV_PATH)
113+
define post_install_pip
114+
$(if $(POST_INSTALL_PIP_ARGS),echo "Applying POST_INSTALL_PIP_ARGS to $(1)" && source $(1)/bin/activate && uv pip install $(POST_INSTALL_PIP_ARGS),true)
115+
endef
116+
98117
# Local wheelhouse for pre-release wheels not yet on an index.
99118
# Exported so every recipe-level uv invocation (uv lock, uv sync, uv venv)
100119
# resolves matching packages from disk without an index lookup. The wildcard
@@ -212,23 +231,29 @@ env-all: _maybe_patch_pyproject
212231
@$(SETUP_ENV) --venv $(VENV) --python-version $(PYTHON_VERSION) --all-groups
213232
@$(call write_active_venv,$(VENV))
214233
@$(ENV_ALL_EXTRAS)
234+
@$(call post_install_pip,$(VENV))
215235

216236
# =============================================================================
217237
# Build
218238
# =============================================================================
219239

220-
# Build the canonical, publishable distribution (wheel + sdist) via the uv build
221-
# frontend. `--no-sources` ignores [tool.uv.sources], so the artifact doesn't
222-
# depend on uv-specific index overrides — the recommended way to build for
223-
# publication. This is what the release workflow runs.
240+
# Build the canonical, publishable distribution (wheel + sdist): the on-tree
241+
# version with any `.dev` suffix stripped (e.g. 0.2.2.dev0 -> 0.2.2), via
242+
# `uv build --no-sources`. `--no-sources` ignores [tool.uv.sources], so the
243+
# artifact doesn't depend on uv-specific index overrides — the recommended way
244+
# to build for publication. This is what the release workflow runs. Routed
245+
# through build.py (like build-dev) so both targets share one code path; set
246+
# COREAI_OPT_VERSION_EXTENSION to insert an extra release segment (see
247+
# RELEASE.md).
224248
build:
225-
@uv build --no-sources
249+
@$(call use_env,VENV) && uv run --no-sync --active python $(SCRIPTS)/make/build.py --no-sources
226250

227-
# Build the development distribution with build.py (standard version; build.py
228-
# also supports a PEP 440 .dev version via --dev). Used by contributors and the
229-
# smoke tests.
251+
# Build a development distribution with build.py: the release base with a
252+
# unique, timestamped PEP 440 dev suffix (e.g. 0.2.2.dev202607231430+abc1234).
253+
# Used by contributors, the smoke tests, and the nightly pipeline. Set
254+
# DEV_VERSION=... to use an exact version instead.
230255
build-dev:
231-
@$(call use_env,VENV) && uv run --no-sync --active python $(SCRIPTS)/make/build.py
256+
@$(call use_env,VENV) && uv run --no-sync --active python $(SCRIPTS)/make/build.py --dev
232257

233258
# =============================================================================
234259
# Code Quality
@@ -277,19 +302,24 @@ test-smoke:
277302
uv run --no-sync --active nox -f $(MAKEFILE_DIR)ci/nox/noxfile.py -s smoke_tests -- $(PYTEST_ARGS) && \
278303
echo "All smoke tests passed!"
279304

280-
# Run tests on lowest supported PyTorch version (pass PYTEST_ARGS for custom flags)
281-
test-lowest-pytorch: env-lowest-torch
305+
# Run tests on lowest supported PyTorch version (pass PYTEST_ARGS for custom flags).
306+
# TORCH_GROUP is already exported, so setting it per target is enough for
307+
# use_env to pick the right torch build. Use `=`, not `:=`: an including
308+
# Makefile may change HIGHEST_TORCH_GROUP after this file is read.
309+
test-lowest-pytorch: TORCH_GROUP = $(LOWEST_TORCH_GROUP)
310+
test-lowest-pytorch:
282311
@echo "Running tests on lowest PyTorch version supported..."
283-
@source $(VENV_LOWEST_TORCH)/bin/activate && \
312+
@$(call use_env,VENV_LOWEST_TORCH) && \
284313
echo "Testing with lowest supported PyTorch versions" && \
285314
uv run --no-sync --active python $(SCRIPTS)/make/log_versions.py && \
286315
$(RUN_TESTS) $(PYTEST_ARGS) && \
287316
echo "All tests passed!"
288317

289318
# Run tests on highest supported PyTorch version (pass PYTEST_ARGS for custom flags)
290-
test-highest-pytorch: env-highest-torch
319+
test-highest-pytorch: TORCH_GROUP = $(HIGHEST_TORCH_GROUP)
320+
test-highest-pytorch:
291321
@echo "Running tests on highest PyTorch version supported..."
292-
@source $(VENV_HIGHEST_TORCH)/bin/activate && \
322+
@$(call use_env,VENV_HIGHEST_TORCH) && \
293323
echo "Testing with latest supported PyTorch versions" && \
294324
uv run --no-sync --active python $(SCRIPTS)/make/log_versions.py && \
295325
$(RUN_TESTS) $(PYTEST_ARGS) && \
@@ -326,9 +356,13 @@ distclean-all:
326356
set-auto-venv:
327357
@$(SCRIPTS)/make/set_auto_venv.sh $(DEFAULT_VENV) $(SHELL_RC)
328358

329-
# Show current version
359+
# Show the development version carried on the tree (e.g. 0.2.2.dev0), including
360+
# any COREAI_OPT_VERSION_EXTENSION (e.g. 0.2.2.1.dev0). Reads _about.py as plain
361+
# text, so no venv is needed — but `uv run --no-project` is still what guarantees
362+
# a >= 3.11 interpreter (a bare `python3` is 3.9 on stock macOS, and `python` may
363+
# not exist at all) without requiring `make env` first.
330364
version:
331-
@python -c "exec(open('$(MAKEFILE_DIR)src/coreai_opt/_about.py').read()); print(__version__)"
365+
@uv run --no-config --no-project --python '>=3.11' $(SCRIPTS)/make/print_version.py
332366

333367
# =============================================================================
334368
# Documentation

RELEASE.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,37 @@
11
# Package Release Guide
22

3-
The OSS release process for Core AI Optimization is being defined. This page will document the workflow for publishing to PyPI once the public release infrastructure is finalized.
3+
The OSS release process for Core AI Optimization is still being defined. This page will document the workflow for publishing to PyPI once the public release infrastructure is finalized.
44

5-
Available locally:
5+
The following commands are available locally:
66

77
```bash
8-
make build # build the package wheel
9-
make version # show current version
8+
make build # build the canonical, publishable wheel + sdist (uv build --no-sources)
9+
make build-dev # build a timestamped dev wheel (e.g. 0.2.2.dev202607231430+abc1234)
10+
make version # show the development version carried on the tree (e.g. 0.2.2.dev0)
1011
make clean # remove build artifacts
1112
```
1213

14+
## Version scheme
15+
16+
`main` always carries the version planned for the _next_ release. This ensures that ongoing development is never mistaken for an already-published version, and that a release can be stabilized, tested, and published on its own branch, independently of later changes on `main`. (The release-branch workflow itself — branch naming, tagging, and backporting fixes to `main` — will be documented separately in the release schedule doc; this section covers only the version-string mechanics.)
17+
18+
`src/coreai_opt/_about.py` stores `latest_released_version` (the last tagged release, e.g. `"0.2.1"`) and computes `__version__` from it by incrementing its last number by one and adding a `.dev0` suffix (e.g. `"0.2.2.dev0"`). A pre-commit hook (`check-about-version`) verifies that `__version__` always follows this rule and that `latest_released_version` matches the repo's latest release tag. As a result, `__version__` can never look as though a release has shipped when it hasn't. The `.dev0` suffix is only a marker on the tree; it never appears in a built wheel.
19+
20+
- `make build` builds the release that `__version__` implies, e.g. `0.2.2`. A release is cut by tagging it (`v0.2.2`); `latest_released_version` is then hard-coded to `"0.2.2"`, which bumps `__version__` to the next candidate (`0.2.3.dev0`).
21+
- `make build-dev` builds that same release but with a unique `.dev<UTC-timestamp>+<short-sha>` suffix instead. It is used by contributors, smoke tests, and the nightly pipeline. `DEV_VERSION=<version>` uses that version exactly instead.
22+
23+
Sorting is preserved: `0.2.2.dev0 < 0.2.2.dev202607231430+abc1234 < 0.2.2`.
24+
25+
### Extending the scheme downstream
26+
27+
A repo that uses this one as a submodule and includes this `Makefile` — building one combined wheel from both trees — can add its own 4th number. Set `COREAI_OPT_VERSION_EXTENSION` to the number it's about to release next (e.g. `"1"` for its first release off a given OSS release, then `"2"` for the one after that). Then call `make build`, `make build-dev`, or `make version` unchanged:
28+
29+
- `latest_released_version` `"0.2.1"` + extension `"1"` -> candidate: `0.2.1.1.dev0`
30+
- `make build` -> `0.2.1.1`
31+
- `make build-dev` -> `0.2.1.1.dev<UTC-timestamp>+<short-sha>`
32+
33+
The extra number is used exactly as given (`scripts/release/release_utils.apply_version_extension`); `latest_released_version`'s own last number is only bumped for OSS's own `main`, when no extension is set.
34+
35+
There is still only one `_about.py` (this package's own); the extra number is a plain string handled entirely in `scripts/release/release_utils.next_release_base` — no other file or package is involved.
36+
1337
<!-- TODO: Document the chosen OSS release workflow (PyPI trusted publishing, twine upload, or uv publish). -->

changelog.d/52.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix per-channel activation quantization crashing with a shape-mismatch `RuntimeError` on MaxPool/AvgPool/AdaptiveAvgPool layers whose shared observer spans an axis the pool shrinks (e.g. a spatial axis under a stride>1 pool). Axes pooling never touches (batch, channel) keep working as per-channel; only the specific unsafe axis falls back to per-tensor, with a warning explaining why and how to pick a safe axis instead.

changelog.d/53.changed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Carry the next planned release with a `.dev0` suffix on `main` (e.g. `0.2.2.dev0`). `make build` strips the suffix for a clean release and `make build-dev` builds a unique, timestamped dev wheel (`0.2.2.dev<timestamp>+<shortsha>`). A repo that vendors this one can insert one extra release segment via the `COREAI_OPT_VERSION_EXTENSION` environment variable to extend the version scheme.

ci/nox/noxfile.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"""
1111

1212
import os
13+
import shlex
1314
import sys
1415
from pathlib import Path
1516

@@ -42,6 +43,12 @@
4243
# resolved against the working directory (the project root, set just below).
4344
SMOKE_TEST_DIST = os.environ.get("SMOKE_TEST_DIST")
4445

46+
# Extra `uv pip install` arguments, applied to the session venv after the
47+
# package under test is installed. Use it to swap a dependency version for one
48+
# run without editing pyproject.toml or the lockfile. Split with shlex so
49+
# quoted version specifiers stay in one piece. Unset means do nothing.
50+
POST_INSTALL_PIP_ARGS = os.environ.get("POST_INSTALL_PIP_ARGS")
51+
4552

4653
@session(
4754
python=get_supported_python_versions(),
@@ -89,6 +96,11 @@ def smoke_tests(session: Session) -> None:
8996
# required on Python 3.12+ where distutils was removed from stdlib.
9097
session.install("setuptools")
9198

99+
# Last, so it replaces any version the installed package pinned.
100+
if POST_INSTALL_PIP_ARGS:
101+
session.log(f"Applying POST_INSTALL_PIP_ARGS: {POST_INSTALL_PIP_ARGS}")
102+
session.install(*shlex.split(POST_INSTALL_PIP_ARGS))
103+
92104
session.log("Running smoke tests")
93105

94106
# Use run_tests.sh to properly handle --junit and other custom flags

docs/src/_static/custom.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ html.dark code.docutils {
7777
font-weight: 600;
7878
}
7979

80+
/* Allow long dotted FQNs to wrap in the sidebar instead of clipping */
81+
.sy-sidebar-toc,
82+
.sy-sidebar-toc ul,
83+
.sy-sidebar-toc li {
84+
overflow: visible;
85+
}
86+
87+
.sy-lside a {
88+
white-space: normal;
89+
word-break: break-word;
90+
}
91+
8092
/* Reset code font in sidebar nav — prevents identifier-titled pages
8193
* from rendering in monospace */
8294
.sy-lside a code {

scripts/make/build.py

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,27 @@
66
"""Build the coreai-opt package.
77
88
Usage:
9-
build.py Build a standard wheel from the current version
10-
build.py --dev Build a dev wheel with a PEP 440 .dev version
9+
build.py --no-sources Build a release: the `.dev` suffix stripped, via
10+
`uv build --no-sources` (ignores [tool.uv.sources];
11+
the recommended way to build the publishable
12+
artifact). Called by `make build`.
13+
build.py --dev Build a dev wheel with a timestamped PEP 440 .dev
14+
version. Called by `make build-dev`.
15+
16+
``_about.py`` stores ``latest_released_version`` (the last tagged release) by
17+
hand; ``__version__`` is computed from it — add one to its last number, add
18+
``.dev0``. This script computes the version to build from
19+
``latest_released_version``, not from the on-tree ``__version__`` (which must
20+
never be treated as already released), writes it into ``_about.py``, builds,
21+
then restores the file. A repo that uses this one as a submodule (building
22+
one combined wheel) can add its own extra number to the version with
23+
``COREAI_OPT_VERSION_EXTENSION``; see
24+
``scripts/release/release_utils.next_release_base``.
1125
"""
1226

1327
from __future__ import annotations
1428

1529
import argparse
16-
import os
1730
import subprocess
1831
import sys
1932
from pathlib import Path
@@ -24,43 +37,71 @@
2437
# internal-only scripts use the explicit `external.scripts.*` form instead.
2538
from scripts._utils import find_repo_root as _find_repo_root
2639
from scripts.release.release_utils import (
27-
get_dev_release_version,
28-
get_package_version,
40+
get_dev_version_override,
41+
get_version_extension,
42+
next_release_base,
43+
read_about,
44+
resolve_build_version,
45+
restore_about,
2946
write_version,
3047
)
3148

3249

33-
def run_build() -> None:
34-
"""Run ``uv build`` to produce the wheel and sdist."""
35-
print(f"Building package with python (version: {sys.version})...")
36-
subprocess.run(["uv", "build"], check=True)
37-
print("Build complete! Check dist/ directory")
50+
def run_build(*, no_sources: bool) -> None:
51+
"""Run ``uv build`` to produce the wheel and sdist.
52+
53+
Args:
54+
no_sources: Pass ``--no-sources`` to ``uv build``, ignoring
55+
``[tool.uv.sources]`` so the artifact doesn't depend on uv-specific
56+
index overrides — used for the publishable release build.
57+
"""
58+
sys.stdout.write(f"Building package with python (version: {sys.version})...\n")
59+
command = ["uv", "build"]
60+
if no_sources:
61+
command.append("--no-sources")
62+
# `uv build` writes to the same stdout, but Python block-buffers when stdout
63+
# isn't a terminal (CI logs, `make build > file`). Flush first so our lines
64+
# don't land after the child's. This also flushes anything buffered earlier,
65+
# so it's the only flush the script needs.
66+
sys.stdout.flush()
67+
subprocess.run(command, check=True)
68+
sys.stdout.write("Build complete! Check dist/ directory\n")
3869

3970

4071
def _build_parser() -> argparse.ArgumentParser:
4172
parser = argparse.ArgumentParser(description="Build the coreai-opt package.")
42-
parser.add_argument(
73+
mode = parser.add_mutually_exclusive_group(required=True)
74+
mode.add_argument(
4375
"--dev",
4476
action="store_true",
45-
help="Build a dev wheel with a PEP 440 .dev version",
77+
help="Build a dev wheel with a timestamped PEP 440 .dev version",
78+
)
79+
mode.add_argument(
80+
"--no-sources",
81+
action="store_true",
82+
help="Build a release via `uv build --no-sources`",
4683
)
4784
return parser
4885

4986

5087
def main() -> None:
5188
args = _build_parser().parse_args()
52-
if not args.dev:
53-
run_build()
54-
return
5589
repo_root = _find_repo_root(Path(__file__))
56-
original_version = get_package_version(repo_root)
57-
dev_version = os.environ.get("DEV_VERSION") or get_dev_release_version(original_version)
90+
91+
about = read_about(repo_root)
92+
release_base = next_release_base(about.latest_released_version, get_version_extension())
93+
build_version = resolve_build_version(
94+
release_base,
95+
dev=args.dev,
96+
dev_version_override=get_dev_version_override(),
97+
)
5898
try:
59-
write_version(repo_root, dev_version)
60-
print(f"Dev version: {dev_version}")
61-
run_build()
99+
write_version(about, build_version)
100+
sys.stdout.write(f"Version: {build_version}\n")
101+
run_build(no_sources=args.no_sources)
62102
finally:
63-
write_version(repo_root, original_version)
103+
# Restore the exact bytes read before the build rewrote the version.
104+
restore_about(about)
64105

65106

66107
if __name__ == "__main__":

0 commit comments

Comments
 (0)