Skip to content

Configure ruff and mypy#60

Draft
marcgibbons wants to merge 26 commits intomainfrom
59-configure-ruff-mypy
Draft

Configure ruff and mypy#60
marcgibbons wants to merge 26 commits intomainfrom
59-configure-ruff-mypy

Conversation

@marcgibbons
Copy link
Contributor

@marcgibbons marcgibbons commented Mar 10, 2026

Closes #59

Summary

ruff

  • Removed deferred suppressions: A001, ANN, ANN401, ARG001, ARG002, E501, EM102, ISC001, N802, PLC0415, PTH, TC002, TID252, TRY003, TRY004
  • Targeted # noqa added inline where the suppression is genuinely needed:
    • N802Field() intentional public API casing
    • ARG001 / ARG002 — args required by calling convention (pydantic-settings abstract interface, loader shims)
    • PLC0415 — lazy imports for optional deps (yaml, toml) and Django
    • ANN401Any on pydantic passthroughs and config field defaults; load() closures properly typed (stream: object, -> dict[str, Any])
  • A001 resolved by renaming internal variable helphelp_text in argparser_add_argument

mypy

  • ignore_errors = true replaced with strict = true and pydantic.mypy plugin
  • tests.* override: disallow_untyped_defs = false, suppress assignment and call-arg false positives from pydantic-settings
  • django-stubs added to dev dependencies
  • Full type annotations added throughout goodconf/

Source fixes (found during annotation work)

  • GoodConfConfigDict fields changed from required to NotRequiredGoodConfConfigDict() is now valid
  • PydanticUndefined imported from pydantic_core (correct export path; was pydantic.fields)
  • initial_for_field raises TypeError instead of ValueError when initial is not callable
  • _find_file uses Path.resolve() instead of os.path.abspath()
  • open(path) replaced with Path(path).open()

tests

  • tmpdir migrated to tmp_path (pathlib.Path) throughout
  • -> None added to all test functions
  • Fixture args annotated: MockerFixture, pytest.MonkeyPatch, pytest.CaptureFixture[str]

pre-commit / CI

  • mypy hook changed to language: system, entry: uv run mypy (uses project venv)
  • ci: skip: [mypy] added so pre-commit.ci skips mypy; local developers still run it on commit
  • mypy step added to test.yml (Python 3.14 only, after tests)
  • .prettierrc.toml added

…EM102)

- Replace os.path calls with pathlib.Path in _load_config and _find_file
- Move tomlkit.items.Item import into TYPE_CHECKING block
- Use absolute imports in goodconf.contrib modules
- Extract exception message variable and change ValueError → TypeError
  for invalid callable check in initial_for_field
- Exclude auto-generated _version.py from ruff
- Remove PTH, TID252, TC002, TRY003, TRY004, EM102 from ruff ignore list
- Add NotRequired to GoodConfConfigDict fields (file_env_var, default_files)
- Annotate loader variable in _load_config as Callable[..., Any]
- Fix _fieldinfo_to_str else branch to return str(annotation)
- Restructure initial_for_field to use isinstance dict check
- Add type: ignore[call-arg] for pydantic default_factory()
- Add type: ignore[assignment] for intentional BaseCommand monkey-patch
- Use walrus operator in argparse.py to narrow default_files type
- Add django-stubs to dev deps for Django type coverage
- Switch mypy pre-commit hook to language: system using uv run
…sion

- Annotate Field(), FileConfigSettingsSource.__init__(), GoodConf._load(),
  get_initial(), generate_yaml/json/toml(), django_manage()
- Annotate argparser_add_argument() and execute_from_command_line_with_config()
- Annotate patched_parser() closure in contrib/django using lazy-imported types
- Annotate tests/utils.env_var()
- Narrow Field json_schema_extra param to dict[str, Any] | None
- Remove ANN from ruff ignore list; only ANN401 (Any) remains suppressed
- Import PydanticUndefined from pydantic_core (explicitly exported)
- Cast PydanticField return value to FieldInfo for no-any-return
- Fix type: ignore code on BaseCommand monkey-patch to [method-assign]
- Enable strict = true in [tool.mypy]
- Run mypy on tests/ in pre-commit hook
- Enable pydantic.mypy plugin
- Add test override: relax untyped-def, suppress pydantic-settings
  false positives for assignment/call-arg
- Use GoodConfConfigDict in test_django.py instead of pydantic ConfigDict
- Fix individual ignores: arg-type, no-redef, attr-defined
- Fix test_goodconf: guard __doc__ None before 'in' check
- Fix test_optional_initial: call G.get_initial() (classmethod, no instance needed)
Using getattr(c, "UNDEFINED") is explicit about intent (runtime attribute
lookup) and removes both the attr-defined type: ignore and noqa: B018.
…CI workflow

- Update mypy hook entry to `uv run mypy goodconf tests` so it runs in
  the project venv rather than requiring a globally installed mypy
- Add .prettierrc.toml for YAML and Markdown formatting
- Add .github/workflows/pre-commit.yml to replace pre-commit.ci;
  installs uv and syncs project deps before running hooks
@codecov
Copy link

codecov bot commented Mar 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.44%. Comparing base (235cc28) to head (8373160).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #60      +/-   ##
==========================================
+ Coverage   98.42%   98.44%   +0.02%     
==========================================
  Files           8        8              
  Lines         380      386       +6     
  Branches        5        5              
==========================================
+ Hits          374      380       +6     
  Misses          3        3              
  Partials        3        3              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configure ruff and mypy

1 participant