-
Notifications
You must be signed in to change notification settings - Fork 3
Upgrade to Python 3.14, enable comprehensive ruff linting, and harden CI #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
48cd4a9
aba113c
1798be9
4207f2f
c19b70f
b09d58e
fc53795
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 3.12 | ||
| 3.14 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "recommendations": [ | ||
| "anthropic.claude-code", | ||
| "ms-vscode-remote.remote-containers", | ||
| "github.vscode-pull-request-github", | ||
| "ms-python.python", | ||
| "charliermarsh.ruff" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,5 @@ | ||
| [tools] | ||
| gh = "latest" | ||
| ollama = "latest" | ||
| python = "3.14" | ||
| uv = "latest" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,7 @@ name = "tapio" | |
| version = "2.0.0" | ||
| description = "An assistant for Finnish immigrants" | ||
| readme = "README.md" | ||
| requires-python = ">=3.10" | ||
| requires-python = ">=3.14" | ||
| license = "MIT" | ||
| authors = [ | ||
| {name = "Finntegrate Team", email = "info@finntegrate.org"} | ||
|
|
@@ -18,10 +18,10 @@ dependencies = [ | |
| "langchain-community>=0.3.21", | ||
| "langchain>=0.3.23", | ||
| "langchain-chroma>=0.2.3", | ||
| "langchain-huggingface>=0.1.2", | ||
| "gradio>=5.25.2", | ||
| "langchain-huggingface[full]>=0.1.2", | ||
| "gradio>=6.0.0", | ||
| "ollama>=0.4.8", | ||
| "pydantic>=2.11.3", | ||
| "pydantic>=2.13.4", | ||
| "httpx>=0.28.1", | ||
| "beautifulsoup4>=4.13.4", | ||
| ] | ||
|
|
@@ -35,11 +35,102 @@ python_files = "test_*.py" | |
|
|
||
| [tool.ruff] | ||
| line-length = 120 | ||
| target-version = "py310" | ||
| target-version = "py314" | ||
|
|
||
| [tool.ruff.lint] | ||
| select = ["E", "F", "I", "UP"] | ||
| ignore = [] | ||
| select = [ | ||
| "A", # flake8-builtins | ||
| "ANN", # flake8-annotations | ||
| "ARG", # flake8-unused-arguments | ||
| "ASYNC", # flake8-async | ||
| "B", # flake8-bugbear | ||
| "BLE", # flake8-blind-except | ||
| "C4", # flake8-comprehensions | ||
| "C90", # mccabe complexity | ||
| "D", # pydocstyle | ||
| "DTZ", # flake8-datetimez | ||
| "E", # pycodestyle errors | ||
| "EM", # flake8-errmsg | ||
| "EXE", # flake8-executable | ||
| "F", # pyflakes | ||
| "FA", # flake8-future-annotations | ||
| "FBT", # flake8-boolean-trap | ||
| "FIX", # flake8-fixme | ||
| "FLY", # flynt | ||
| "FURB", # refurb | ||
| "G", # flake8-logging-format | ||
| "I", # isort | ||
| "ICN", # flake8-import-conventions | ||
| "INP", # flake8-no-pep420 | ||
| "ISC", # flake8-implicit-str-concat | ||
| "LOG", # flake8-logging | ||
| "N", # pep8-naming | ||
| "PERF", # perflint | ||
| "PGH", # pygrep-hooks | ||
| "PIE", # flake8-pie | ||
| "PL", # pylint | ||
| "PT", # flake8-pytest-style | ||
| "PTH", # flake8-use-pathlib | ||
| "RET", # flake8-return | ||
| "RSE", # flake8-raise | ||
| "RUF", # ruff-specific rules | ||
| "S", # flake8-bandit | ||
| "SIM", # flake8-simplify | ||
| "SLF", # flake8-self | ||
| "SLOT", # flake8-slots | ||
| "T10", # flake8-debugger | ||
| "T20", # flake8-print | ||
| "TC", # flake8-type-checking | ||
| "TD", # flake8-todos | ||
| "TID", # flake8-tidy-imports | ||
| "TRY", # tryceratops | ||
| "UP", # pyupgrade | ||
| "W", # pycodestyle warnings | ||
| "YTT", # flake8-2020 | ||
| ] | ||
| ignore = [ | ||
| "ANN401", # Any is used intentionally for flexible metadata dicts | ||
| "BLE001", # broad except-and-log-and-continue is intentional throughout the crawl/parse/vectorize pipelines | ||
| "COM812", # trailing-comma rules conflict with the ruff formatter | ||
| "FBT001", # bool positional params are idiomatic for typer.Option-based CLI flags | ||
| "FBT002", # bool default params are idiomatic for typer.Option-based CLI flags | ||
| "ISC001", # implicit-str-concat conflicts with the ruff formatter | ||
| "TC001", # moving first-party imports behind TYPE_CHECKING breaks at runtime: no | ||
| # `from __future__ import annotations` here, and Python 3.14's deferred | ||
| # annotations (PEP 649) only postpone evaluation -- anything that actually | ||
| # resolves them (e.g. gradio's event-handler introspection, already hit a | ||
| # NameError on this) still needs the name to exist at call time | ||
| "TC002", # same risk as TC001, for third-party imports | ||
| "TC003", # same risk as TC001, for standard-library imports | ||
| "TRY301", # raise typer.Exit(...) inside a try block is a deliberate CLI control-flow | ||
| # signal for validation failures, not an error needing a dedicated wrapper | ||
| # function -- tryceratops' heuristic doesn't fit this idiom | ||
| ] | ||
|
|
||
| [tool.ruff.lint.per-file-ignores] | ||
| "tests/*" = [ | ||
| "ANN", # tests are excluded from mypy and don't need type annotations | ||
| "ARG001", # unused fixture/mock arguments are normal in tests | ||
| "ARG002", # unused mock-override arguments are normal in tests | ||
| "D", # docstrings aren't required on test functions | ||
| "INP001", # tests intentionally use implicit namespace packages | ||
| "PLC0415", # local imports for mocking/patching timing are idiomatic in tests | ||
| "PLR0913", # test functions naturally take many fixture arguments | ||
| "PLR2004", # magic values in test assertions/fixtures are fine | ||
| "PT009", # some test classes intentionally use unittest.TestCase-style assertions | ||
| "PTH", # os.path-based temp file/dir handling in test fixtures is fine | ||
| "S101", # assert is the standard pytest idiom | ||
| "SLF001", # tests intentionally exercise private members | ||
| ] | ||
|
Comment on lines
+110
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🌐 Web query:
💡 Result: In Ruff, a Citations:
🌐 Web query:
💡 Result: In Ruff, the per-file-ignores setting supports glob patterns to match files or directories for which specific lint rules should be disabled [1][2]. For recursive directory matching—where you want to apply ignores to all files within a directory and its subdirectories—the standard approach is to use the double wildcard pattern [2][3]. Recommended Patterns: 1. Recursive Matching (Recommended for most test directories): To ignore rules for all Python files throughout an entire directory tree, use the pattern "tests//.py" [2]. [tool.ruff.lint.per-file-ignores] "tests//.py" = ["D"] 2. Non-Recursive Matching: Using "tests/" targets files directly within the "tests/" directory [2]. Depending on your specific Ruff version and configuration, this may not consistently cover nested subdirectories [2][4]. Key Implementation Details: - Location: This setting is typically configured in your pyproject.toml or ruff.toml file under the [tool.ruff.lint.per-file-ignores] section [5][1][2]. - Syntax: The patterns are evaluated as glob patterns [1][2]. You can specify a list of rule codes or prefixes to ignore for the matched files [1]. - Negation: You can use an initial '!' to negate a file pattern if needed [1]. - Consistency: While some simpler glob patterns might behave differently across tool settings (like exclude vs. per-file-ignores), using the explicit recursive syntax (/.py) is the most reliable way to target all files in a directory hierarchy [2][6]. Citations:
🌐 Web query:
💡 Result: To apply per-file-ignores recursively to all files within a tests directory and its nested subdirectories, you should use the globstar pattern in your configuration. In your configuration file (e.g., pyproject.toml or ruff.toml), define the per-file-ignores setting using a pattern like the following [1][2][3]: [tool.ruff.lint.per-file-ignores] "tests/" = ["RULE_CODE"] The pattern ensures that the rule is applied recursively to all files within the tests directory and any of its nested subdirectories [4]. If you need to target specific file types within those directories, you can append the extension, for example: "tests//*.py" = ["RULE_CODE"] This configuration instructs the linter to exclude the specified rule codes for any matching file found at any depth under the tests directory [2]. Citations:
🌐 Web query:
💡 Result: In Ruff, the Citations:
🌐 Web query:
💡 Result: Ruff's per-file-ignores setting supports glob patterns to match files or directories for which specific lint rules should be ignored [1][2][3]. These patterns are defined in your configuration file (e.g., pyproject.toml or ruff.toml) under the [tool.ruff.lint.per-file-ignores] section [1][4][5]. Key syntax points: - Recursive matching: Use to match files recursively through subdirectories [3][5]. For example, "tests//.py" matches all Python files within the tests directory and any of its subdirectories [5]. - Brace expansion: Ruff supports brace expansion, allowing you to group multiple paths or extensions [1][6]. For example, "/{tests,docs,tools}/" ignores violations in any of those directories [1][4]. - Negation: You can use a leading! to negate a pattern [2][3]. This is useful for "ignore everywhere except" scenarios, such as "!src/.py" = ["D"] to ignore Pydocstyle (D) rules in every file except those in the src directory [2][3]. - Path context: Patterns are relative to the project root (the directory containing your configuration file) [7]. - Configuration: You map these patterns to a list of rule codes or prefixes [2][5]. Example configuration (pyproject.toml): [tool.ruff.lint.per-file-ignores] # Ignore D (Pydocstyle) in all files within the tests directory recursively "tests//.py" = ["D"] # Ignore E402 in specific directories using brace expansion "/{tests,docs,tools}/" = ["E402"] # Ignore D everywhere except the src directory "!src/.py" = ["D"] Note that file pattern syntax in Ruff can occasionally behave differently depending on whether you are using per-file-ignores or the top-level exclude setting [8]. It is recommended to verify your configuration using ruff show-settings if you encounter unexpected matching behavior [8]. Citations:
🌐 Web query:
💡 Result: In the context of the Ruff linter, you can use recursive globbing within the per-file-ignores setting [1][2]. Ruff supports standard glob patterns for file matching in the per-file-ignores configuration [3][1]. To ignore rules recursively across all files within a specific directory, you can use the double asterisk globstar pattern [1][2]. For example, to ignore rule E402 for all files within a tests directory and its subdirectories, you can use the following configuration in your pyproject.toml: [tool.ruff.lint.per-file-ignores] "/tests/" = ["E402"] Alternatively, you can group multiple directories: [tool.ruff.lint.per-file-ignores] "/{tests,docs}/" = ["E402"] Note that while the original Flake8 tool also supports per-file-ignores, its pattern matching capabilities are more limited compared to Ruff, and it does not natively support recursive globstar patterns in the same way. If you are specifically looking for recursive support, Ruff is the recommended, modern alternative that provides this functionality [1][2]. Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- pyproject.toml excerpt ---'
sed -n '110,124p' pyproject.toml
printf '\n%s\n' '--- tests tree (depth 3) ---'
find tests -maxdepth 3 -type f | sort | sed -n '1,200p'Repository: Finntegrate/tapio Length of output: 1895 🌐 Web query:
💡 Result: In glob patterns, the double asterisk is known as a globstar or recursive wildcard [1]. It matches any directory, subdirectory, or file recursively within the specified path [1]. When used in the per-file-ignores configuration of tools like the Ruff linter, the pattern allows you to apply rule exclusions to files across a directory tree [2][3]. For example, a pattern like "/{tests,docs,tools}/" will match and apply the specified ignore rules to all files nested within the tests, docs, or tools directories, regardless of their depth in the project structure [2][3]. Key points regarding the recursive double asterisk in this context: - Recursive Matching: Unlike a single asterisk (), which typically matches files only within a single directory level, enables deep, recursive traversal of the file system [1]. - Configuration Usage: It is commonly used in configuration files (such as pyproject.toml or ruff.toml) to selectively disable specific linting rules for large portions of a project, such as test suites or generated documentation, without needing to list every individual file or subdirectory [2][3]. - Paths: Patterns are generally treated as relative to the project root, meaning at the start of a pattern refers to the entire directory structure relative to that root [4][2]. Citations:
🌐 Web query:
💡 Result: In Ruff, you can use the lint.per-file-ignores setting to disable specific lint rules for files or directories that match a given pattern [1][2]. To ignore rules for files within the tests directory, you can add an entry to your pyproject.toml or ruff.toml file under the [tool.ruff.lint.per-file-ignores] section [1][2]. Example configuration: [tool.ruff.lint.per-file-ignores] "tests/" = ["E402", "F401"] In this example, the rules E402 and F401 will be ignored for all files contained within the tests directory [1][2]. Key details: - Pattern Matching: Ruff uses glob patterns [2]. "tests/" will match files directly inside the tests directory, while "/{tests}/" or "tests//" can be used to match files recursively within the tests directory and its subdirectories [1][2]. - Configuration: This setting must be placed under [tool.ruff.lint.per-file-ignores] if using pyproject.toml [1][2]. - CLI: While there is no dedicated CLI flag for every configuration, you can use the --per-file-ignores flag or the --config flag to override these settings from the command line [1]. Citations: 🌐 Web query:
💡 Result: In Ruff, the behavior of glob matching—specifically whether the asterisk () character matches path separators (slashes)—can be complex and has been a subject of ongoing discussion and refinement [1][2]. Officially, Ruff's glob implementation uses the globset crate [1]. Historically, the default behavior of the globset library allows * to match path separators, which means a pattern like src/.py might inadvertently match files in subdirectories (e.g., src/subdir/file.py) in addition to files directly within the directory [1][2]. Key points regarding Ruff's glob matching in per-file-ignores: 1. Path Separator Matching: Because * matches path separators by default, patterns intended to be single-level often behave as multi-level, recursive matches [1][2]. Users have reported this as an issue where, for example, src/.py matches files deeper in the directory tree than expected [2]. 2. Limitations and Configuration: There is no simple toggle in the current user-facing configuration to disable this "match-slash" behavior [1]. While internal efforts to apply literal_separator(true) to glob patterns (which restricts * from matching slashes) have been discussed and implemented in some parts of the codebase, behavior may remain inconsistent across different settings like exclude and per-file-ignores [2][3]. 3. Recommended Practice: To avoid ambiguity or unexpected matches, use explicit recursive patterns like /.py if you intend to match all files in a tree, or target files more specifically [4][5]. If you need to match files only at a specific depth, the current implementation's tendency to treat * as matching slashes necessitates caution [2]. Because Ruff's internal glob handling is evolving, and behaviors can vary depending on the specific version and configuration context (e.g., CLI vs. file-based settings), it is best to verify your patterns using the specific Ruff version you are running if you require strict path-level matching [6][7][2]. Citations:
🌐 Web query:
💡 Result: In tools like Ruff, the per-file-ignores setting supports recursive matching within subdirectories by using glob patterns [1]. To apply ignore rules to all files within a specific directory and its subdirectories, you can use the double-star glob pattern [1]. For example, to ignore specific rule codes for all files within a tests directory and any of its subdirectories, you would use the following configuration in your pyproject.toml or ruff.toml file [1]: [tool.ruff.lint.per-file-ignores] "tests//.py" = ["RULE1", "RULE2"] Using "tests/" typically matches files directly within the tests directory, whereas "tests//*.py" ensures that the pattern recurses into all nested subdirectories [1]. You can also use the! prefix to negate patterns or define complex inclusion/exclusion logic as needed [1]. Citations: Make the Ruff test ignore recursive. 🤖 Prompt for AI Agents |
||
| "tapio/cli.py" = [ | ||
| "FBT003", # typer.Option(False, ...) passes the default positionally by convention | ||
| ] | ||
|
|
||
| [tool.ruff.lint.pydocstyle] | ||
| convention = "google" | ||
|
|
||
| [tool.ruff.lint.pylint] | ||
| max-args = 6 | ||
|
|
||
| [tool.ruff.format] | ||
| quote-style = "double" | ||
|
|
@@ -49,12 +140,12 @@ line-ending = "auto" | |
| [dependency-groups] | ||
| dev = [ | ||
| "mypy>=1.15.0", | ||
| "pre-commit>=4.2.0", | ||
| "pyrefly>=0.17.0", | ||
| "prek>=0.2.3", | ||
| "pyrefly>=1.1.1", | ||
| "pytest>=8.3.5", | ||
| "pytest-asyncio>=1.0.0", | ||
| "pytest-cov>=6.1.1", | ||
| "ruff>=0.11.5", | ||
| "ruff>=0.13.1", | ||
| "types-lxml>=2025.3.30", | ||
| "types-pyyaml>=6.0.12.20250402", | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| project_includes = ["tapio/", ] | ||
| project_excludes = ["**/.[!/.]*", "**/*venv/**", ".venv/**", "tests/"] | ||
| search_path = ["tapio/", "tests/"] | ||
| python_version = "3.11.0" | ||
| python_version = "3.14.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,4 +8,3 @@ filterwarnings = | |
|
|
||
| markers = | ||
| integration: Integration tests that use real components (slower, may download models) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.