Skip to content

Controlling scope of build options #1235

Closed
@JukkaL

Description

@JukkaL

Currently the --implicit-any mode flag is global, as it uniformly affects how mypy processes every file in a mypy run. Other global flags are being considered or implemented, including --strict and the "weak mode". Similarly, we could have options to disable/enable individual errors/warnings. These kinds of mode flags have some inconvenient properties, and I elaborate on this below.

A. Combining type checked programs is hard

It's hard to combine two independently developed codebases into a single type checked program, as it may be necessary to use the least common denominator options to type check the combined program without spurious warnings. Global flags effectively introduce multiple mypy dialects that aren't quite compatible. Using the least common denominator options is clearly not desirable as programmers likely chose to enable some options for their code for a good reason.

Integrating multiple pieces of code without loosening type checking may involve a lot of refactoring or adding # type: ignore comments.

B. Migrating to stricter type checking mode is hard

Migrating from the default mode to --strict, for example, would have to be performed for the whole code base to avoid generating warnings. If there is, say, millions of lines code, this can be a huge undertaking, and may require the co-operation of owners of every part of the codebase. It would be much nicer to migrate to stricter options gradually, similar to how mypy supports migration from dynamic to static typing in small increments. This would also give more flexibility to owners of particular modules.

C. Options aren't self-documenting

When just looking at a source file, it's not obvious under which options it's supposed to type checked. This is less of a problem within a single, uniform codebase, but it becomes more important when combining code from multiple sources. It's easy to "forget" that some files should be checked in the strict mode when copying or moving source code, for example, since the knowledge lives in external configuration such as build scripts instead of being close to the physical code.


Here are some ways to overcome some of these problems:

  1. We type check code bases with different global options using separate mypy runs, stubbing out dependencies. So if codebases A and B have different global options, and A depends on B, we first type check B using the desired options and generate a set of stub files. We then separately type check A using a different set of options, and using stubs for B. This increases complexity and requires additional tooling to automatically generate stubs. Additionally, this doesn't significantly simplify the migration to stricter options within a single codebase.
  2. Provide fine grained configuration outside source files. For example, perhaps mypy will accept options such as --strict=package1,package2 that will enforce some options for particular packages only. Alternatively, we could have a configuration file with rules such as strict=package/**,module, or perhaps even a hierarchy of such configuration files. This provides more flexibility but it makes it easy to forget to modify the configuration when adding new files or moving files around.
  3. Provide per-file option flags. We always default to some well-defined mode, and we support comments such as # mypy: strict near the top of the file that change mode options for that file only. This is very flexible and it makes files self-contained, but it's easy to forget to add the desired options to new files. We could also have a tool that enforces that certain options are always used in certain packages, similar to (2) above, in addition to per-file comments.
  4. Don't provide any options. Make the default mode "good enough" for most people.

My proposal is to choose some variant of option 3.


Note that I don't consider --silent-import a global option because it only affects files not being processed, so it's not really problematic in the same sense as the other options I discussed above.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions