Skip to content

Type the plugin and internal API surfaces - #4014

Open
gaborbernat wants to merge 2 commits into
tox-dev:mainfrom
gaborbernat:typed-api
Open

Type the plugin and internal API surfaces#4014
gaborbernat wants to merge 2 commits into
tox-dev:mainfrom
gaborbernat:typed-api

Conversation

@gaborbernat

Copy link
Copy Markdown
Member

Plugin authors get typed APIs where tox handed them Any, and the code base now passes three type
checkers: ty (the existing gate), mypy in strict mode, and pyrefly.

For plugin authors

  • conf.get("key", Type) returns a configuration value verified at runtime against its declared type, so plugins can
    drop the cast they wrap around conf["key"] today. The untyped conf["key"] read stays as is.
  • The tox_on_install hook and Installer.install receive InstallArguments, a named union of what tox installs
    (requirements file, pylock file, or a sequence of requirements and packages). Installer grew a second type
    parameter defaulting to that union, so existing Installer[MyEnv] subclasses keep working.
  • Parsed declares the CLI option surface: options.recreate and friends complete in editors and type-check.
  • add_config accepts default=None for optional values and infers the value type from callable defaults.
  • The journal, the environment cache, and execute metadata hold JsonValue content; structured set_env entries
    match the new SetEnvEntry shape; package modes and run modes are Literal types.

Guard rails

  • tox r -e type now runs mypy (strict) and pyrefly after ty; all three pass, and each keeps its own command so ty
    stays fast. Suppressions name the specific error code and the reason (usually an upstream stub gap or a checker
    inference limit, e.g. wrong inference of function literals off subclass-of types astral-sh/ty#2428, which this change works around for six of its seven call sites).
  • tests/type_check/ pins the inference behavior of the new APIs with assert_type files all three checkers read.
  • typing-extensions becomes a runtime dependency below Python 3.13 to supply TypeVar defaults.

Fixes the stricter checks surfaced

  • colorama colors were annotated int throughout reporting, yet hold ANSI escape strings.
  • A pyproject.toml where tool.tox or env_base is not a table produced a traceback; both now report an
    error (or fall back to other configuration sources during discovery).
  • The structured { product = ... } form accepted a non-list exclude; it now rejects it.

Beyond those three, runtime behavior does not change.

Replace Any on the surfaces plugins build against:

* ConfigSet.get(key, of_type) reads a config value verified against
  its declared type, replacing cast() around conf["key"] reads
* tox_on_install and Installer type arguments as InstallArguments; a
  second Installer type parameter (defaulting to that union) lets
  subclasses narrow it while Installer[Env] keeps working
* Parsed declares the CLI option surface so options.<name> type-checks
* add_config accepts default=None, infers value types from callable
  defaults, and drops six of the seven ty overload suppressions
* journal, env cache, and execute metadata content is JsonValue;
  structured set_env entries match SetEnvEntry; package modes, run
  modes, and the replacer dispatch use Literal types

The type env now gates mypy --strict and pyrefly next to ty; all
three pass. typing-extensions becomes a runtime dependency below
Python 3.13 for TypeVar defaults. The stricter checks surfaced two
fixes: colorama colors were annotated int yet hold strings, and a
non-table tool.tox or env_base in pyproject.toml no longer crashes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant