Skip to content
Open
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
10 changes: 10 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ please follow these guidelines:
- **Exception**: Explicit re-export patterns like `from ... import X as X` or marked with "# For export"
- This prevents circular imports and makes dependencies clear

## Python Import Style Guidelines

* **Default to Module-Qualified Imports:** Prefer importing whole modules and using qualified calls (e.g., `import math; math.sqrt(16)` or `import pandas as pd; pd.DataFrame()`) to prevent namespace pollution, avoid name clashes, and provide immediate context for where functions or objects originate.
* **Use Direct Symbol Imports Cautiously:** Restrict direct imports (`from module import symbol`) to specific scenarios where they genuinely improve readability or adhere to standard conventions:
Comment thread
bmerkle marked this conversation as resolved.
* Importing classes, exceptions, or constants (e.g., `from my_project.models import User`).
* Avoiding severe, repetitive visual clutter in heavy mathematical or algorithmic code.
* Standard library patterns (e.g., `from collections import defaultdict, Counter`).
* **Exception**: In `tests/`, importing functions directly to call them in assertions is idiomatic pytest style and is not held to this restriction (see #298).
* **Prohibit Wildcard Imports:** Never use wildcard imports (`from module import *`) in normal code. **Exception**: the same explicit re-export aggregator pattern allowed by the Import Architecture Rules above (e.g. `interfaces.py` re-exporting `interfaces_core`, `interfaces_indexes`, etc. with `__all__`) — enforced by `make ruff` (see Makefile), with that file listed in `[tool.ruff.lint.per-file-ignores]`.

Comment on lines +123 to +132

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe ruff has some rules that enforce this, or at the very least, can be enabled, these sort of things should be deterministic and triggered by pre-commit / CI linting, it's context engineering best practices.

@bmerkle Bernhard Merkle (bmerkle) Aug 26, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point, and for context this isn't new ground — I raised almost this exact question in #116 ("consider ruff as alternative to black and isort etc"). Guido van Rossum (@gvanrossum) and I went back and forth on it there (Ruff's isort-compatible config, mixed import/from ordering, etc.), and I closed it once #132 landed a working isort profile that covers the ordering piece we needed at the time: "via #132 we have now a working isort profile in place, so IMO we do not need to consider ruff further, at least for now."

That said, your comment is really about a narrower and separate gap: isort only sorts/groups imports, it doesn't ban wildcard imports or enforce the qualified-vs-direct-import heuristic documented here. Neither of those was in scope of the #116 discussion. The wildcard-ban part is genuinely a one-line, zero-config win with ruff (F403/F405 are in its default rule set) — the qualified-vs-direct heuristic isn't something a standard rule enforces automatically (it needs to distinguish "is this a class/exception/constant", which isn't purely mechanical).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I just remembered that I had the same conversation with guido at some point and he didn't change his mind either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with that in mind

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went ahead and added this: ruff is now a dev dependency with a make ruff target (63c62d8), scoped to F403/F405 (wildcard-import ban) since that's the one piece of this guideline that's genuinely mechanical to enforce. interfaces.py's sanctioned re-export aggregator is carved out via a per-file-ignore, and I tightened the AGENTS.md wildcard-import bullet to explicitly name that exception so the doc and the linter agree.

Not wired into make all/CI yet — following the same staged approach Guido van Rossum (@gvanrossum) suggested back in #116 ("make a small PR that allows us to run make ruff, adding it to CI is a separate step"). Let me know if you'd like CI wiring folded into this PR too, or tracked as the immediate next step.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kevin Turcios (@KRRT7) I have added first ruff integration, so we can run it locally and proceed incrementally.
Thanks for bringing up the idea again :-)

* Order imports alphabetically after lowercasing; group them as follows
(with a blank line between groups):
1. standard library imports
Expand Down
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ format: venv
uv run isort src tests tools examples $(FLAGS)
uv run black -tpy312 src tests tools examples $(FLAGS)

# intentionally running pyright only for the lowest and the highest version
# intentionally running pyright only for the lowest and the highest version
# running it for all versions takes too much time and doesn't add enough diagnostic power
.PHONY: check
check: venv
uv run pyright --pythonversion 3.12 src tests tools examples
uv run pyright --pythonversion 3.15 src tests tools examples

# Not wired into 'all'/CI yet -- see #116. Narrowly scoped for now to
Comment thread
bmerkle marked this conversation as resolved.
# deterministically banning wildcard imports (AGENTS.md's import guidelines).
.PHONY: ruff
ruff: venv
uv run ruff check src tests tools examples

.PHONY: test
test: venv
uv run pytest $(FLAGS)
Expand Down Expand Up @@ -105,6 +111,7 @@ help:
@echo "make all # venv, format, check, test, build"
@echo "make format # Run isort and black"
@echo "make check # Run pyright"
@echo "make ruff # Run ruff (wildcard-import checks only, not part of 'all' yet)"
@echo "make test # Run pytest (tests are in tests/)"
@echo "make coverage # Run tests with coverage"
@echo "make build # Build the wheel (under dist/)"
Expand Down
11 changes: 10 additions & 1 deletion make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ if defined ARGS set "ARGS=%ARGS:~1%"
:dispatch
if /I "%CMD%"=="format" goto format
if /I "%CMD%"=="check" goto check
if /I "%CMD%"=="ruff" goto ruff
if /I "%CMD%"=="test" goto test
if /I "%CMD%"=="coverage" goto coverage
if /I "%CMD%"=="demo" goto demo
Expand Down Expand Up @@ -59,6 +60,14 @@ uv run pyright --pythonversion 3.12 src tests tools examples || exit /b 1
uv run pyright --pythonversion 3.15 src tests tools examples || exit /b 1
goto end

:: Not wired into CI yet -- see #116. Narrowly scoped for now to
:: deterministically banning wildcard imports (AGENTS.md's import guidelines).
:ruff
if not exist ".venv\" call make.bat venv
echo Running ruff...
uv run ruff check src tests tools examples || exit /b 1
goto end

:test
if not exist ".venv\" call make.bat venv
echo Running unit tests...
Expand Down Expand Up @@ -123,7 +132,7 @@ if exist .pytest_cache rmdir /s /q .pytest_cache
goto end

:help
echo Usage: .\make [format^|check^|test^|coverage^|demo^|build^|venv^|sync^|install-uv^|clean^|help]
echo Usage: .\make [format^|check^|ruff^|test^|coverage^|demo^|build^|venv^|sync^|install-uv^|clean^|help]
goto end

:end
14 changes: 14 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ known_ai = ["mcp", "openai", "pydantic", "pydantic_ai", "tiktoken", "typechat"]
known_first_party = ["typeagent", "tests", "tools", "gmail", "demo"]
known_local_folder = ["conftest"]

# isort/black/pyright already cover ordering, formatting and unused/duplicate
# imports (see above). Ruff is scoped narrowly to the one gap those don't
# fill: deterministically banning wildcard imports, per AGENTS.md's "Python
# Import Style Guidelines". Broader adoption of ruff as an isort/black
# replacement was considered and deferred in #116.
[tool.ruff.lint]
select = ["F403", "F405"]

[tool.ruff.lint.per-file-ignores]
# Explicit re-export aggregator (see AGENTS.md's "Import Architecture Rules"
# and "Prohibit Wildcard Imports" exceptions).
"src/typeagent/knowpro/interfaces.py" = ["F403", "F405"]

[dependency-groups]

# Dev tooling never reaches the wheel metadata -- these bounds only pick which
Expand All @@ -118,4 +131,5 @@ dev = [
"pytest>=9.1.1",
"pytest-asyncio>=1.4.0",
"pytest-mock>=3.15.1",
"ruff>=0.16.4",
]
27 changes: 27 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading