-
Notifications
You must be signed in to change notification settings - Fork 0
Changes: Create time_tracker.py in app/core/. Add funct
#83
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
Conversation
…functions `start_timer(report_id)` and `finish_timer(report_id)` that recor
WalkthroughAdded a .gitignore file to exclude virtual environment directories and Python cache artifacts. Removed virtual environment bin scripts (python, python3, python3.12) from the repository, consolidating project housekeeping by preventing future tracking of environment-specific files. Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
backend/app/core/time_tracker.py (2)
9-19: Consider using lazy formatting in logger calls.The function logic is correct and error handling is appropriate. However, f-strings in logger calls are evaluated eagerly even when the log level would skip them, which can impact performance in high-throughput scenarios.
Apply this diff to use lazy % formatting:
- logger.info(f"Timer started for report_id: {report_id} at {start_time}") + logger.info("Timer started for report_id: %s at %s", report_id, start_time)- logger.error(f"Failed to start timer for report_id {report_id}: {e}", exc_info=True) + logger.error("Failed to start timer for report_id %s: %s", report_id, e, exc_info=True)
34-34: Consider using lazy formatting in logger calls.Similar to
start_timer, these logger calls use f-strings that are evaluated eagerly. For consistency and performance, use lazy % formatting.Apply this diff:
- logger.info(f"Timer finished for report_id: {report_id}. Duration: {duration:.2f} seconds.") + logger.info("Timer finished for report_id: %s. Duration: %.2f seconds.", report_id, duration)- logger.warning(f"Timer not found for report_id: {report_id}") + logger.warning("Timer not found for report_id: %s", report_id)- logger.error(f"Failed to finish timer for report_id {report_id}: {e}", exc_info=True) + logger.error("Failed to finish timer for report_id %s: %s", report_id, e, exc_info=True)Also applies to: 37-37, 40-40
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
backend/app/core/time_tracker.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
backend/app/core/time_tracker.py (1)
backend/app/cache/redis_client.py (3)
set_cache(37-49)get_cache(51-63)delete_cache(65-75)
🔇 Additional comments (2)
backend/app/core/time_tracker.py (2)
1-7: LGTM!The imports and module setup are correct. The Redis key prefix provides clear namespace isolation for timer keys.
21-21: Document Python version requirement or usefrom __future__ import annotationsfor compatibility.The
float | Nonesyntax (PEP 604) requires Python 3.10 or higher. This pattern is used throughout the codebase, suggesting intentional targeting of Python 3.10+. However, there is no explicit Python version requirement inpyproject.tomlorsetup.py. Either addpython_requires = ">=3.10"to your project configuration, or usefrom __future__ import annotations(available in Python 3.7+) to enable this syntax on earlier versions.
backend/app/core/time_tracker.py
Outdated
| start_time_str = redis_client.get_cache(key) | ||
| if start_time_str: | ||
| redis_client.delete_cache(key) | ||
| start_time = datetime.fromisoformat(start_time_str) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Redis returns bytes, not strings.
Line 31 will raise a TypeError because redis_client.get_cache() returns bytes from the Redis client, but datetime.fromisoformat() expects a string. You must decode the bytes before parsing.
Apply this diff to fix the issue:
start_time_str = redis_client.get_cache(key)
if start_time_str:
redis_client.delete_cache(key)
- start_time = datetime.fromisoformat(start_time_str)
+ start_time = datetime.fromisoformat(start_time_str.decode('utf-8'))
end_time = datetime.now()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| start_time_str = redis_client.get_cache(key) | |
| if start_time_str: | |
| redis_client.delete_cache(key) | |
| start_time = datetime.fromisoformat(start_time_str) | |
| start_time_str = redis_client.get_cache(key) | |
| if start_time_str: | |
| redis_client.delete_cache(key) | |
| start_time = datetime.fromisoformat(start_time_str.decode('utf-8')) |
🤖 Prompt for AI Agents
In backend/app/core/time_tracker.py around lines 28 to 31,
redis_client.get_cache() returns bytes but the code passes that directly to
datetime.fromisoformat(), causing a TypeError; decode the returned value to a
string (e.g., call .decode('utf-8') or use .decode() if not None) before calling
datetime.fromisoformat(), and optionally guard with an isinstance check or a
conditional to only decode when the value is bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 26
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
♻️ Duplicate comments (22)
.venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/METADATA (1)
1-242: Same issue: virtual environment file should not be committed.This file is part of the same
.venv/directory that should be excluded from version control. See the previous comment on the RECORD file..venv/lib/python3.12/site-packages/_pytest/_code/__init__.py (1)
1-24: Virtual environment file - should not be committed.Same issue as noted above. This pytest library file should be removed along with the entire
.venv/directory..venv/lib/python3.12/site-packages/_pytest/_code/code.py (1)
1-1411: Virtual environment file - should not be committed.Same issue as noted above. This pytest library file should be removed along with the entire
.venv/directory..venv/bin/fastapi (1)
1-8: Virtualenv shim should not be tracked (duplicate of pip3.12 comment)This FastAPI CLI wrapper is a generated
.venvscript with a local-path shebang and no project-specific logic. It should be removed from git along with the rest of.venv(see comment on.venv/bin/pip3.12)..venv/bin/uvicorn (1)
1-8: Generated uvicorn launcher should not live in source controlThis is another venv-generated entrypoint with an absolute shebang. It should be excluded from the repo together with the rest of
.venv(see.venv/bin/pip3.12review)..venv/bin/alembic (1)
1-8: Alembic CLI shim is environment-specific and shouldn’t be committedThis wrapper is auto-generated by the virtualenv and depends on a hard-coded path. Remove it (and
.venvgenerally) from version control; rely onpip install+alembicfrom the venv instead..venv/bin/dotenv (1)
1-8: Dotenv CLI wrapper is a generated artifactAs with the other
.venv/bin/*scripts, this is a generated launcher and should not be versioned. Please remove it along with the rest of the virtualenv directory..venv/bin/nltk (1)
1-8: NLTK launcher is venv-generated and should be excludedThis script is produced by the venv tooling and includes an absolute shebang. It should not be tracked; prefer ignoring
.venv/entirely..venv/bin/tqdm (1)
1-8: Tqdm CLI shim is not application codeThis is another auto-generated
.venv/binscript. Please remove it from git and rely on recreating the venv frompyproject.toml/requirements.txtinstead..venv/bin/normalizer (1)
1-8: Charset-normalizer CLI shim should be removed with the venvThis is a virtualenv-generated entrypoint and not part of the app’s source. Please delete it (and
.venvcontents) from version control and ensure.venv/is ignored going forward..venv/bin/activate.fish (1)
1-69: Auto-generated virtual environment file should not be committed.This Fish shell activation script is auto-generated by Python's
venvmodule and contains a hardcoded path on line 36 specific to the original developer's machine. As noted in the previous file, the entire.venv/directory should be added to.gitignoreand removed from version control..venv/bin/Activate.ps1 (1)
1-247: Auto-generated virtual environment file should not be committed.This PowerShell activation script is auto-generated by Python's
venvmodule. While it dynamically derives paths, the entire.venv/directory should be excluded from version control as previously noted..venv/bin/activate.csh (1)
1-27: Auto-generated virtual environment file should not be committed.This C shell activation script contains a hardcoded path on line 12. As noted previously, remove the
.venv/directory from version control..venv/bin/activate (1)
1-70: Auto-generated virtual environment file should not be committed.This Bash activation script contains hardcoded paths on lines 42 and 45. As noted previously, the entire
.venv/directory should be removed from version control and added to.gitignore.Additionally: The PR description states this adds
time_tracker.pyinapp/core/with timer functions, but none of the files under review match that description. Please verify that the intendedtime_tracker.pyfile is included in this PR and that these.venv/files were not accidentally staged..venv/lib/python3.12/site-packages/_pytest/__init__.py (1)
1-10: Virtual environment file - should not be committed.This is the pytest package's
__init__.pyfrom the virtual environment. As noted in the previous file, all.venv/contents should be removed from this PR and added to.gitignore..venv/lib/python3.12/site-packages/_pytest/_io/wcwidth.py (1)
1-55: Virtual environment file - should not be committed.This pytest terminal width utility module is part of the virtual environment and should not be in version control.
.venv/lib/python3.12/site-packages/_pytest/assertion/truncate.py (1)
1-118: Virtual environment file - should not be committed.This is pytest's assertion truncation module from the virtual environment. The static analysis warnings (unused
max_lengthparameter on line 21, loop variable on line 106) are in third-party pytest code and not within your control to fix.Remove all
.venv/files from this PR..venv/lib/python3.12/site-packages/_pytest/_io/pprint.py (1)
1-676: Virtual environment file - should not be committed.This is pytest's vendored pretty-printer (originally from CPython) located in the virtual environment. The static analysis warnings are expected in vendored third-party code and are not actionable.
Summary for this PR: None of the 5 files submitted for review should be committed. They are all pytest library files from
.venv/. The actualtime_tracker.pyfile mentioned in the PR description (app/core/time_tracker.pywithstart_timerandfinish_timerfunctions) is not present in this review.Please:
- Remove
.venv/from git tracking:git rm -r --cached .venv/- Add
.venv/to.gitignore- Ensure the intended
app/core/time_tracker.pyfile is properly staged and committed.venv/lib/python3.12/site-packages/_pytest/_io/terminalwriter.py (1)
1-245: Virtual environment file - should not be committed.This is a third-party
pytestlibrary file. See the comment on.venv/lib/python3.12/site-packages/_pytest/assertion/__init__.pyfor remediation steps..venv/lib/python3.12/site-packages/_pytest/debugging.py (1)
1-392: Virtual environment file - should not be committed.This is a third-party
pytestlibrary file. See the comment on.venv/lib/python3.12/site-packages/_pytest/assertion/__init__.pyfor remediation steps..venv/lib/python3.12/site-packages/_pytest/assertion/util.py (1)
1-609: Virtual environment file - should not be committed.This is a third-party
pytestlibrary file. See the comment on.venv/lib/python3.12/site-packages/_pytest/assertion/__init__.pyfor remediation steps..venv/lib/python3.12/site-packages/_pytest/assertion/rewrite.py (1)
1-1191: Virtual environment file - should not be committed.This is a third-party
pytestlibrary file. See the comment on.venv/lib/python3.12/site-packages/_pytest/assertion/__init__.pyfor remediation steps.
🟠 Major comments (3)
.venv/bin/py.test-1-8 (1)
1-8: Do not commit virtualenv-generated pytest launcher scriptsThis file is an auto-generated shim inside
.venv/with an absolute shebang pointing to your local path:
- Line 1 hardcodes
/home/repositories/.../.venv/bin/python3, which will not exist on other machines or CI.- Everything under
.venv/is environment-specific and should generally be excluded from version control.Recommend:
- Remove
.venv/bin/py.test(and other.venvcontents) from the repo.- Add
.venv/to.gitignore(or equivalent) so these artifacts are not tracked.- Rely on
pytestfrom the active virtualenv instead of this committed shim..venv/lib/python3.12/site-packages/_pytest/deprecated.py-1-89 (1)
1-89: Do not commit.venv/ site-packages; this file is third‑party and unrelated to the PR goalThis module is part of pytest inside a virtualenv (
.venv/lib/python3.12/site-packages/_pytest/...), not application code. Checking in.venv/site-packageswill bloat the repo and tightly couple it to a specific local environment, and any edits here will be overwritten on dependency upgrades.
- Please remove this file (and the rest of
.venv) from version control and add.venv/to.gitignore(or equivalent ignore mechanism).- The PR description mentions adding
app/core/time_tracker.pywithstart_timer/finish_timer, but that file is not present in the diff you shared. Make sure only your actual application code (e.g.,app/core/time_tracker.py) and any necessary tests/config are included in the PR, not generated environment artifacts..venv/bin/pip3.12-1-8 (1)
1-8: Do not commit virtualenv binaries to the repositoryThis is an auto-generated pip shim inside
.venvwith a machine-specific shebang. Keeping these in git will:
- Break on other machines/paths.
- Create noisy diffs whenever the venv is recreated or upgraded.
- Bloat the repo with generated tooling.
Recommend:
- Remove the entire
.venv/directory from version control.- Add it to
.gitignore(or equivalent) so only application code (e.g.,app/core/time_tracker.pymentioned in the PR description) is tracked.Example
.gitignoresnippet:+.venv/Committable suggestion skipped: line range outside the PR's diff.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (127)
.venv/lib/python3.12/site-packages/__pycache__/py.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/__pycache__/typing_extensions.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/_argcomplete.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/_version.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/cacheprovider.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/capture.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/compat.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/debugging.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/deprecated.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/doctest.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/faulthandler.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/fixtures.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/freeze_support.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/helpconfig.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/hookspec.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/junitxml.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/legacypath.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/logging.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/main.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/monkeypatch.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/nodes.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/outcomes.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/pastebin.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/pathlib.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/pytester.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/pytester_assertions.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/python.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/python_api.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/python_path.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/recwarn.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/reports.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/runner.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/scope.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/setuponly.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/setupplan.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/skipping.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/stash.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/stepwise.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/terminal.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/threadexception.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/timing.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/tmpdir.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/unittest.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/unraisableexception.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/warning_types.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/__pycache__/warnings.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_code/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_code/__pycache__/code.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_code/__pycache__/source.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_io/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_io/__pycache__/pprint.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_io/__pycache__/saferepr.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_io/__pycache__/terminalwriter.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_io/__pycache__/wcwidth.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_py/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_py/__pycache__/error.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/_py/__pycache__/path.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/assertion/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/assertion/__pycache__/rewrite.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/assertion/__pycache__/truncate.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/assertion/__pycache__/util.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/config/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/config/__pycache__/argparsing.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/config/__pycache__/compat.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/config/__pycache__/exceptions.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/config/__pycache__/findpaths.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/mark/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/mark/__pycache__/expression.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/_pytest/mark/__pycache__/structures.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/__main__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/command.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/config.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/context.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/environment.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/migration.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/__pycache__/op.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/autogenerate/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/autogenerate/__pycache__/api.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/autogenerate/__pycache__/compare.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/autogenerate/__pycache__/render.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/autogenerate/__pycache__/rewriter.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/base.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/impl.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/mssql.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/mysql.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/oracle.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/postgresql.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/ddl/__pycache__/sqlite.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/operations/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/operations/__pycache__/base.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/operations/__pycache__/batch.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/operations/__pycache__/ops.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/operations/__pycache__/schemaobj.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/operations/__pycache__/toimpl.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/runtime/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/runtime/__pycache__/environment.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/runtime/__pycache__/migration.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/script/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/script/__pycache__/base.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/script/__pycache__/revision.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/script/__pycache__/write_hooks.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/templates/async/__pycache__/env.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/templates/generic/__pycache__/env.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/templates/multidb/__pycache__/env.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/assertions.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/env.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/fixtures.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/requirements.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/schemacompare.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/util.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/__pycache__/warnings.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/plugin/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/plugin/__pycache__/bootstrap.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/_autogen_fixtures.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/test_autogen_comments.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/test_autogen_computed.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/test_autogen_diffs.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/test_autogen_fks.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/test_autogen_identity.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/test_environment.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/testing/suite/__pycache__/test_op.cpython-312.pycis excluded by!**/*.pyc.venv/lib/python3.12/site-packages/alembic/util/__pycache__/__init__.cpython-312.pycis excluded by!**/*.pyc
📒 Files selected for processing (60)
.venv/bin/Activate.ps1(1 hunks).venv/bin/activate(1 hunks).venv/bin/activate.csh(1 hunks).venv/bin/activate.fish(1 hunks).venv/bin/alembic(1 hunks).venv/bin/dotenv(1 hunks).venv/bin/fastapi(1 hunks).venv/bin/httpx(1 hunks).venv/bin/mako-render(1 hunks).venv/bin/nltk(1 hunks).venv/bin/normalizer(1 hunks).venv/bin/pip(1 hunks).venv/bin/pip3(1 hunks).venv/bin/pip3.12(1 hunks).venv/bin/py.test(1 hunks).venv/bin/pytest(1 hunks).venv/bin/tqdm(1 hunks).venv/bin/uvicorn(1 hunks).venv/include/site/python3.12/greenlet/greenlet.h(1 hunks).venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/INSTALLER(1 hunks).venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/LICENSE(1 hunks).venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/METADATA(1 hunks).venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/RECORD(1 hunks).venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/WHEEL(1 hunks).venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/top_level.txt(1 hunks).venv/lib/python3.12/site-packages/_pytest/__init__.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_argcomplete.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_code/__init__.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_code/code.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_code/source.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_io/__init__.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_io/pprint.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_io/saferepr.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_io/terminalwriter.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_io/wcwidth.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_py/error.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_py/path.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/_version.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/assertion/__init__.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/assertion/rewrite.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/assertion/truncate.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/assertion/util.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/cacheprovider.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/capture.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/compat.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/config/__init__.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/config/argparsing.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/config/compat.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/config/exceptions.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/config/findpaths.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/debugging.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/deprecated.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/doctest.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/faulthandler.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/fixtures.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/freeze_support.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/helpconfig.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/hookspec.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/junitxml.py(1 hunks).venv/lib/python3.12/site-packages/_pytest/legacypath.py(1 hunks)
✅ Files skipped from review due to trivial changes (8)
- .venv/bin/httpx
- .venv/bin/pip3
- .venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/LICENSE
- .venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/top_level.txt
- .venv/bin/pytest
- .venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/WHEEL
- .venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/INSTALLER
- .venv/bin/pip
🧰 Additional context used
🪛 Clang (14.0.6)
.venv/include/site/python3.12/greenlet/greenlet.h
[error] 9-9: 'Python.h' file not found
(clang-diagnostic-error)
🪛 Ruff (0.14.7)
.venv/lib/python3.12/site-packages/_pytest/_argcomplete.py
80-80: Unused method argument: kwargs
(ARG002)
.venv/lib/python3.12/site-packages/_pytest/_io/saferepr.py
11-11: Do not catch blind exception: BaseException
(BLE001)
20-20: Do not catch blind exception: BaseException
(BLE001)
65-65: Do not catch blind exception: BaseException
(BLE001)
71-71: Unused method argument: level
(ARG002)
76-76: Do not catch blind exception: BaseException
(BLE001)
91-91: Do not catch blind exception: Exception
(BLE001)
129-129: Do not catch blind exception: Exception
(BLE001)
.venv/lib/python3.12/site-packages/_pytest/_py/error.py
58-58: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
98-98: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
103-103: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
.venv/lib/python3.12/site-packages/_pytest/_io/pprint.py
83-83: Avoid specifying long messages outside the exception class
(TRY003)
85-85: Avoid specifying long messages outside the exception class
(TRY003)
87-87: Avoid specifying long messages outside the exception class
(TRY003)
155-155: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
255-255: Unused method argument: context
(ARG002)
314-314: Unused method argument: context
(ARG002)
397-397: Unused method argument: allowance
(ARG002)
421-421: Unused method argument: allowance
(ARG002)
458-458: Unused method argument: allowance
(ARG002)
.venv/lib/python3.12/site-packages/_pytest/config/compat.py
28-31: Avoid specifying long messages outside the exception class
(TRY003)
.venv/lib/python3.12/site-packages/_pytest/doctest.py
488-488: No explicit stacklevel keyword argument found
Set stacklevel=2
(B028)
658-658: zip() without an explicit strict= parameter
Add explicit value for parameter strict=
(B905)
.venv/lib/python3.12/site-packages/_pytest/legacypath.py
398-398: Unused function argument: name
(ARG001)
407-407: Avoid specifying long messages outside the exception class
(TRY003)
.venv/lib/python3.12/site-packages/_pytest/faulthandler.py
59-59: Abstract raise to an inner function
(TRY301)
60-60: Consider moving this statement to an else block
(TRY300)
.venv/lib/python3.12/site-packages/_pytest/cacheprovider.py
147-147: Avoid specifying long messages outside the exception class
(TRY003)
405-405: Unused method argument: session
(ARG002)
573-573: Unused function argument: session
(ARG001)
.venv/lib/python3.12/site-packages/_pytest/_code/__init__.py
14-24: __all__ is not sorted
Apply an isort-style sorting to __all__
(RUF022)
.venv/lib/python3.12/site-packages/_pytest/_code/source.py
60-60: Avoid specifying long messages outside the exception class
(TRY003)
99-99: Avoid specifying long messages outside the exception class
(TRY003)
100-100: Unpacked variable ast is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
121-121: Do not catch blind exception: Exception
(BLE001)
135-135: Using hasattr(x, "__call__") to test if x is callable is unreliable. Use callable(x) for consistent results.
(B004)
138-138: Avoid specifying long messages outside the exception class
(TRY003)
174-174: Unused function argument: assertion
(ARG001)
207-208: try-except-pass detected, consider logging the exception
(S110)
207-207: Do not catch blind exception: Exception
(BLE001)
.venv/lib/python3.12/site-packages/_pytest/config/findpaths.py
73-73: Avoid specifying long messages outside the exception class
(TRY003)
219-221: Avoid specifying long messages outside the exception class
(TRY003)
.venv/lib/python3.12/site-packages/_pytest/compat.py
229-229: Loop control variable i not used within loop body
Rename unused i to _i
(B007)
244-246: Avoid specifying long messages outside the exception class
(TRY003)
259-259: Do not catch blind exception: Exception
(BLE001)
294-294: Do not catch blind exception: Exception
(BLE001)
351-351: Do not assert False (python -O removes these calls), raise AssertionError()
Replace assert False
(B011)
.venv/lib/python3.12/site-packages/_pytest/junitxml.py
72-72: Loop control variable kr not used within loop body
Rename unused kr to _kr
(B007)
190-190: Unused method argument: report
(ARG002)
195-195: Unused method argument: report
(ARG002)
372-372: Unused function argument: value
(ARG001)
.venv/lib/python3.12/site-packages/_pytest/_io/terminalwriter.py
45-66: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
103-103: Avoid specifying long messages outside the exception class
(TRY003)
187-189: Avoid specifying long messages outside the exception class
(TRY003)
194-194: zip() without an explicit strict= parameter
Add explicit value for parameter strict=
(B905)
.venv/lib/python3.12/site-packages/_pytest/debugging.py
41-43: Avoid specifying long messages outside the exception class
(TRY003)
72-72: Import for pdb found
(T100)
105-105: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
118-118: Import for pdb found
(T100)
142-144: Avoid specifying long messages outside the exception class
(TRY003)
146-146: Import for pdb found
(T100)
240-240: Unused class method argument: args
(ARG003)
.venv/lib/python3.12/site-packages/_pytest/assertion/truncate.py
21-21: Unused function argument: max_length
(ARG001)
106-106: Loop control variable iterated_index not used within loop body
(B007)
.venv/lib/python3.12/site-packages/_pytest/assertion/rewrite.py
45-45: Unused noqa directive (non-enabled: F401)
Remove unused noqa directive
(RUF100)
60-60: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
Parenthesize the and subexpression
(RUF021)
97-97: Unused method argument: target
(ARG002)
134-134: Unused method argument: spec
(ARG002)
178-178: Use of exec detected
(S102)
356-356: Unused lambda argument: x
(ARG005)
394-394: Deserialization with the marshal module is possibly dangerous
(S302)
395-395: Do not catch blind exception: Exception
(BLE001)
469-469: Do not catch blind exception: Exception
(BLE001)
474-474: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
Parenthesize the and subexpression
(RUF021)
484-484: Loop control variable i not used within loop body
(B007)
484-484: Loop control variable expl not used within loop body
(B007)
484-484: zip() without an explicit strict= parameter
Add explicit value for parameter strict=
(B905)
487-487: Do not catch blind exception: Exception
(BLE001)
753-753: Loop control variable i not used within loop body
Rename unused i to _i
(B007)
1119-1119: zip() without an explicit strict= parameter
Add explicit value for parameter strict=
(B905)
.venv/lib/python3.12/site-packages/_pytest/_code/code.py
97-97: Abstract raise to an inner function
(TRY301)
97-97: Avoid specifying long messages outside the exception class
(TRY003)
98-98: Consider moving this statement to an else block
(TRY300)
171-171: Use of possibly insecure function; consider using ast.literal_eval
(S307)
292-293: try-except-pass detected, consider logging the exception
(S110)
292-292: Do not catch blind exception: Exception
(BLE001)
306-306: Do not catch blind exception: BaseException
(BLE001)
824-824: Do not catch blind exception: BaseException
(BLE001)
829-829: Do not catch blind exception: BaseException
(BLE001)
945-945: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
Parenthesize the and subexpression
(RUF021)
1016-1016: Do not catch blind exception: Exception
(BLE001)
1182-1183: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
Parenthesize the and subexpression
(RUF021)
1361-1361: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
Parenthesize the and subexpression
(RUF021)
.venv/lib/python3.12/site-packages/_pytest/fixtures.py
296-296: FuncFixtureInfo.__slots__ is not sorted
Apply a natural sort to FuncFixtureInfo.__slots__
(RUF023)
423-425: Avoid specifying long messages outside the exception class
(TRY003)
432-432: Avoid specifying long messages outside the exception class
(TRY003)
448-448: Avoid specifying long messages outside the exception class
(TRY003)
457-457: Avoid specifying long messages outside the exception class
(TRY003)
807-807: Loop control variable i not used within loop body
Rename unused i to _i
(B007)
879-879: Avoid specifying long messages outside the exception class
(TRY003)
916-919: Avoid specifying long messages outside the exception class
(TRY003)
1010-1010: Do not catch blind exception: BaseException
(BLE001)
1150-1150: Unused function argument: args
(ARG001)
1150-1150: Unused function argument: kwargs
(ARG001)
1178-1178: Avoid specifying long messages outside the exception class
(TRY003)
1181-1183: Avoid specifying long messages outside the exception class
(TRY003)
1868-1868: Loop control variable argname not used within loop body
(B007)
1889-1889: Loop control variable baseid not used within loop body
Rename unused baseid to _baseid
(B007)
.venv/lib/python3.12/site-packages/_pytest/helpconfig.py
40-40: Unused method argument: values
(ARG002)
40-40: Unused method argument: option_string
(ARG002)
182-182: Unpacked variable default is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
186-186: Avoid specifying long messages outside the exception class
(TRY003)
.venv/lib/python3.12/site-packages/_pytest/config/argparsing.py
87-87: Loop control variable i not used within loop body
(B007)
292-292: Avoid specifying long messages outside the exception class
(TRY003)
398-398: Avoid specifying long messages outside the exception class
(TRY003)
.venv/lib/python3.12/site-packages/_pytest/config/__init__.py
208-208: Consider moving this statement to an else block
(TRY300)
228-228: Avoid specifying long messages outside the exception class
(TRY003)
239-239: Avoid specifying long messages outside the exception class
(TRY003)
349-349: Consider moving this statement to an else block
(TRY300)
446-447: try-except-pass detected, consider logging the exception
(S110)
446-446: Do not catch blind exception: Exception
(BLE001)
499-499: No explicit stacklevel keyword argument found
Set stacklevel=2
(B028)
735-739: Avoid specifying long messages outside the exception class
(TRY003)
1149-1149: Unused method argument: pluginmanager
(ARG002)
1222-1222: Unpacked variable args_source is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
1275-1275: Unpacked variable unknown_args is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
1442-1444: Avoid specifying long messages outside the exception class
(TRY003)
1597-1597: Unused method argument: name
(ARG002)
1603-1603: Unpacked variable description is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
1605-1605: Avoid specifying long messages outside the exception class
(TRY003)
1679-1681: Avoid specifying long messages outside the exception class
(TRY003)
1700-1700: Abstract raise to an inner function
(TRY301)
1701-1701: Consider moving this statement to an else block
(TRY300)
1709-1709: Avoid specifying long messages outside the exception class
(TRY003)
1711-1711: Unused method argument: path
(ARG002)
1715-1715: Unused method argument: path
(ARG002)
1823-1823: Do not assert False (python -O removes these calls), raise AssertionError()
Replace assert False
(B011)
1869-1869: Avoid specifying long messages outside the exception class
(TRY003)
1922-1922: Do not catch blind exception: Exception
(BLE001)
1934-1934: Abstract raise to an inner function
(TRY301)
1934-1934: Avoid specifying long messages outside the exception class
(TRY003)
1962-1962: Avoid specifying long messages outside the exception class
(TRY003)
.venv/lib/python3.12/site-packages/_pytest/assertion/util.py
145-145: Do not catch blind exception: Exception
(BLE001)
225-225: Do not catch blind exception: Exception
(BLE001)
358-358: Unused function argument: verbose
(ARG001)
419-419: Unused function argument: verbose
(ARG001)
431-431: Unused function argument: verbose
(ARG001)
443-443: Unused function argument: verbose
(ARG001)
455-455: Unused function argument: verbose
(ARG001)
464-464: Unused function argument: verbose
(ARG001)
544-544: Do not call getattr with a constant attribute value. It is not any safer than normal property access.
Replace getattr with attribute access
(B009)
548-548: Do not assert False (python -O removes these calls), raise AssertionError()
Replace assert False
(B011)
.venv/lib/python3.12/site-packages/_pytest/capture.py
76-76: Unused noqa directive (non-enabled: F401)
Remove unused noqa directive
(RUF100)
206-206: Unused method argument: size
(ARG002)
207-209: Avoid specifying long messages outside the exception class
(TRY003)
216-216: Unused method argument: hint
(ARG002)
217-219: Avoid specifying long messages outside the exception class
(TRY003)
225-225: Avoid specifying long messages outside the exception class
(TRY003)
228-228: Avoid specifying long messages outside the exception class
(TRY003)
239-239: Unused method argument: offset
(ARG002)
239-239: Unused method argument: whence
(ARG002)
240-240: Avoid specifying long messages outside the exception class
(TRY003)
246-246: Avoid specifying long messages outside the exception class
(TRY003)
248-248: Unused method argument: size
(ARG002)
249-249: Avoid specifying long messages outside the exception class
(TRY003)
251-251: Unused method argument: data
(ARG002)
252-252: Avoid specifying long messages outside the exception class
(TRY003)
254-254: Unused method argument: lines
(ARG002)
255-255: Avoid specifying long messages outside the exception class
(TRY003)
359-359: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
Parenthesize the and subexpression
(RUF021)
368-368: Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
Parenthesize the and subexpression
(RUF021)
598-598: Unused noqa directive (non-enabled: PYI024)
Remove unused noqa directive
(RUF100)
670-670: Avoid specifying long messages outside the exception class
(TRY003)
701-701: Avoid specifying long messages outside the exception class
(TRY003)
.venv/lib/python3.12/site-packages/_pytest/_py/path.py
86-86: Avoid specifying long messages outside the exception class
(TRY003)
144-144: Using hasattr(x, "__call__") to test if x is callable is unreliable. Use callable(x) for consistent results.
Replace with callable()
(B004)
145-145: Unused lambda argument: path
(ARG005)
293-296: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
293-296: Avoid specifying long messages outside the exception class
(TRY003)
438-438: Avoid specifying long messages outside the exception class
(TRY003)
478-478: Consider moving this statement to an else block
(TRY300)
512-512: zip() without an explicit strict= parameter
Add explicit value for parameter strict=
(B905)
544-544: Using hasattr(x, "__call__") to test if x is callable is unreliable. Use callable(x) for consistent results.
Replace with callable()
(B004)
631-631: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
631-631: Avoid specifying long messages outside the exception class
(TRY003)
657-657: Unpacked variable basename is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
803-803: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
920-920: Avoid specifying long messages outside the exception class
(TRY003)
977-977: Do not catch blind exception: Exception
(BLE001)
1041-1041: Avoid specifying long messages outside the exception class
(TRY003)
1101-1101: Avoid specifying long messages outside the exception class
(TRY003)
1155-1155: Use of exec detected
(S102)
1171-1171: subprocess call: check for execution of untrusted input
(S603)
1406-1407: try-except-pass detected, consider logging the exception
(S110)
1406-1406: Do not catch blind exception: Exception
(BLE001)
1413-1414: try-except-pass detected, consider logging the exception
(S110)
1413-1413: Do not catch blind exception: Exception
(BLE001)
.venv/lib/python3.12/site-packages/_pytest/hookspec.py
22-22: Import for pdb found
(T100)
🔇 Additional comments (2)
.venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/METADATA (1)
1-3: PR objectives mismatch: expectedtime_tracker.pynot found.The PR description states this adds
app/core/time_tracker.pywithstart_timerandfinish_timerfunctions, but the files provided for review are virtual environment artifacts unrelated to that feature. Please ensure the actual feature code is included in this PR and remove the.venv/files..venv/lib/python3.12/site-packages/_pytest/_py/path.py (1)
1-1477: Do not commit the.venv/directory to version control.This file is part of the pytest library installed in your virtual environment. Committing
.venv/is a well-known anti-pattern that causes:
- Repository bloat — Virtual environments contain thousands of files and can be hundreds of MB
- Platform incompatibility — Compiled extensions (
.so,.pyd) are platform-specific- Dependency management issues — Updates and security patches become manual operations
Add
.venv/to your.gitignoreand remove this directory from the repository. Dependencies should be managed viapip install -r requirements.txt.Additionally, verify that the PR includes the intended changes mentioned in the objectives (e.g.,
app/core/time_tracker.pywithstart_timerandfinish_timerfunctions).
.venv/bin/mako-render
Outdated
| #!/home/repositories/LumintelAnalytics/ChainReport-API/.venv/bin/python3 | ||
| # -*- coding: utf-8 -*- | ||
| import re | ||
| import sys | ||
| from mako.cmd import cmdline | ||
| if __name__ == '__main__': | ||
| sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) | ||
| sys.exit(cmdline()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not commit virtual environment files to version control.
This file is auto-generated by pip when installing packages and contains a hardcoded absolute path (/home/repositories/LumintelAnalytics/ChainReport-API/.venv/bin/python3) that will not work on other developers' machines or CI/CD environments.
The entire .venv/ directory should be excluded from version control. Add it to .gitignore:
+# Virtual environment
+.venv/
+venv/
+ENV/Then remove the committed .venv/ directory:
git rm -r --cached .venv/🤖 Prompt for AI Agents
.venv/bin/mako-render lines 1-8: this is a generated virtualenv script
containing an absolute interpreter path and should not be committed; remove the
entire .venv directory from the repo and add .venv/ to .gitignore, then run git
rm -r --cached .venv/ (or delete the folder and commit the removal) and commit
the updated .gitignore so the virtual environment and its generated scripts are
no longer tracked.
| /* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ | ||
|
|
||
| /* Greenlet object interface */ | ||
|
|
||
| #ifndef Py_GREENLETOBJECT_H | ||
| #define Py_GREENLETOBJECT_H | ||
|
|
||
|
|
||
| #include <Python.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /* This is deprecated and undocumented. It does not change. */ | ||
| #define GREENLET_VERSION "1.0.0" | ||
|
|
||
| #ifndef GREENLET_MODULE | ||
| #define implementation_ptr_t void* | ||
| #endif | ||
|
|
||
| typedef struct _greenlet { | ||
| PyObject_HEAD | ||
| PyObject* weakreflist; | ||
| PyObject* dict; | ||
| implementation_ptr_t pimpl; | ||
| } PyGreenlet; | ||
|
|
||
| #define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) | ||
|
|
||
|
|
||
| /* C API functions */ | ||
|
|
||
| /* Total number of symbols that are exported */ | ||
| #define PyGreenlet_API_pointers 12 | ||
|
|
||
| #define PyGreenlet_Type_NUM 0 | ||
| #define PyExc_GreenletError_NUM 1 | ||
| #define PyExc_GreenletExit_NUM 2 | ||
|
|
||
| #define PyGreenlet_New_NUM 3 | ||
| #define PyGreenlet_GetCurrent_NUM 4 | ||
| #define PyGreenlet_Throw_NUM 5 | ||
| #define PyGreenlet_Switch_NUM 6 | ||
| #define PyGreenlet_SetParent_NUM 7 | ||
|
|
||
| #define PyGreenlet_MAIN_NUM 8 | ||
| #define PyGreenlet_STARTED_NUM 9 | ||
| #define PyGreenlet_ACTIVE_NUM 10 | ||
| #define PyGreenlet_GET_PARENT_NUM 11 | ||
|
|
||
| #ifndef GREENLET_MODULE | ||
| /* This section is used by modules that uses the greenlet C API */ | ||
| static void** _PyGreenlet_API = NULL; | ||
|
|
||
| # define PyGreenlet_Type \ | ||
| (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) | ||
|
|
||
| # define PyExc_GreenletError \ | ||
| ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) | ||
|
|
||
| # define PyExc_GreenletExit \ | ||
| ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) | ||
|
|
||
| /* | ||
| * PyGreenlet_New(PyObject *args) | ||
| * | ||
| * greenlet.greenlet(run, parent=None) | ||
| */ | ||
| # define PyGreenlet_New \ | ||
| (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ | ||
| _PyGreenlet_API[PyGreenlet_New_NUM]) | ||
|
|
||
| /* | ||
| * PyGreenlet_GetCurrent(void) | ||
| * | ||
| * greenlet.getcurrent() | ||
| */ | ||
| # define PyGreenlet_GetCurrent \ | ||
| (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) | ||
|
|
||
| /* | ||
| * PyGreenlet_Throw( | ||
| * PyGreenlet *greenlet, | ||
| * PyObject *typ, | ||
| * PyObject *val, | ||
| * PyObject *tb) | ||
| * | ||
| * g.throw(...) | ||
| */ | ||
| # define PyGreenlet_Throw \ | ||
| (*(PyObject * (*)(PyGreenlet * self, \ | ||
| PyObject * typ, \ | ||
| PyObject * val, \ | ||
| PyObject * tb)) \ | ||
| _PyGreenlet_API[PyGreenlet_Throw_NUM]) | ||
|
|
||
| /* | ||
| * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) | ||
| * | ||
| * g.switch(*args, **kwargs) | ||
| */ | ||
| # define PyGreenlet_Switch \ | ||
| (*(PyObject * \ | ||
| (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ | ||
| _PyGreenlet_API[PyGreenlet_Switch_NUM]) | ||
|
|
||
| /* | ||
| * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) | ||
| * | ||
| * g.parent = new_parent | ||
| */ | ||
| # define PyGreenlet_SetParent \ | ||
| (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ | ||
| _PyGreenlet_API[PyGreenlet_SetParent_NUM]) | ||
|
|
||
| /* | ||
| * PyGreenlet_GetParent(PyObject* greenlet) | ||
| * | ||
| * return greenlet.parent; | ||
| * | ||
| * This could return NULL even if there is no exception active. | ||
| * If it does not return NULL, you are responsible for decrementing the | ||
| * reference count. | ||
| */ | ||
| # define PyGreenlet_GetParent \ | ||
| (*(PyGreenlet* (*)(PyGreenlet*)) \ | ||
| _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) | ||
|
|
||
| /* | ||
| * deprecated, undocumented alias. | ||
| */ | ||
| # define PyGreenlet_GET_PARENT PyGreenlet_GetParent | ||
|
|
||
| # define PyGreenlet_MAIN \ | ||
| (*(int (*)(PyGreenlet*)) \ | ||
| _PyGreenlet_API[PyGreenlet_MAIN_NUM]) | ||
|
|
||
| # define PyGreenlet_STARTED \ | ||
| (*(int (*)(PyGreenlet*)) \ | ||
| _PyGreenlet_API[PyGreenlet_STARTED_NUM]) | ||
|
|
||
| # define PyGreenlet_ACTIVE \ | ||
| (*(int (*)(PyGreenlet*)) \ | ||
| _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) | ||
|
|
||
|
|
||
|
|
||
|
|
||
| /* Macro that imports greenlet and initializes C API */ | ||
| /* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we | ||
| keep the older definition to be sure older code that might have a copy of | ||
| the header still works. */ | ||
| # define PyGreenlet_Import() \ | ||
| { \ | ||
| _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ | ||
| } | ||
|
|
||
| #endif /* GREENLET_MODULE */ | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
| #endif /* !Py_GREENLETOBJECT_H */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not commit virtual environment files to version control.
This file is part of the .venv/ directory, which is a Python virtual environment containing installed dependencies. Virtual environment directories should never be committed to version control because:
- They are auto-generated and can be recreated from
requirements.txtorpyproject.toml - They bloat the repository significantly (can be hundreds of MBs)
- They contain platform-specific binaries that may not work across different systems
- They create unnecessary merge conflicts
Additionally, this file (greenlet C header) is unrelated to the stated PR objective of adding time_tracker.py in app/core/.
Recommended actions:
- Remove the entire
.venv/directory from the commit - Add
.venv/to your.gitignorefile:
+# Virtual environments
+.venv/
+venv/
+ENV/
+env/- If you accidentally committed
.venv/, remove it from git tracking:
git rm -r --cached .venv/Regarding the static analysis hint about Python.h not found — this is expected for header files meant to be used in build environments with Python development headers installed. However, since this file should not be committed at all, this warning is moot.
🧰 Tools
🪛 Clang (14.0.6)
[error] 9-9: 'Python.h' file not found
(clang-diagnostic-error)
🤖 Prompt for AI Agents
.venv/include/site/python3.12/greenlet/greenlet.h lines 1-164: This file is
inside a committed .venv virtual environment and should not be in the repo;
remove the entire .venv directory from the commit, add “.venv/” to .gitignore,
stop tracking any already committed files with git rm -r --cached .venv/ (then
commit the removal), and ensure your PR only contains the intended change
(app/core/time_tracker.py) before pushing the corrected commit(s).
| """Allow bash-completion for argparse with argcomplete if installed. | ||
|
|
||
| Needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail | ||
| to find the magic string, so _ARGCOMPLETE env. var is never set, and | ||
| this does not need special code). | ||
|
|
||
| Function try_argcomplete(parser) should be called directly before | ||
| the call to ArgumentParser.parse_args(). | ||
|
|
||
| The filescompleter is what you normally would use on the positional | ||
| arguments specification, in order to get "dirname/" after "dirn<TAB>" | ||
| instead of the default "dirname ": | ||
|
|
||
| optparser.add_argument(Config._file_or_dir, nargs='*').completer=filescompleter | ||
|
|
||
| Other, application specific, completers should go in the file | ||
| doing the add_argument calls as they need to be specified as .completer | ||
| attributes as well. (If argcomplete is not installed, the function the | ||
| attribute points to will not be used). | ||
|
|
||
| SPEEDUP | ||
| ======= | ||
|
|
||
| The generic argcomplete script for bash-completion | ||
| (/etc/bash_completion.d/python-argcomplete.sh) | ||
| uses a python program to determine startup script generated by pip. | ||
| You can speed up completion somewhat by changing this script to include | ||
| # PYTHON_ARGCOMPLETE_OK | ||
| so the python-argcomplete-check-easy-install-script does not | ||
| need to be called to find the entry point of the code and see if that is | ||
| marked with PYTHON_ARGCOMPLETE_OK. | ||
|
|
||
| INSTALL/DEBUGGING | ||
| ================= | ||
|
|
||
| To include this support in another application that has setup.py generated | ||
| scripts: | ||
|
|
||
| - Add the line: | ||
| # PYTHON_ARGCOMPLETE_OK | ||
| near the top of the main python entry point. | ||
|
|
||
| - Include in the file calling parse_args(): | ||
| from _argcomplete import try_argcomplete, filescompleter | ||
| Call try_argcomplete just before parse_args(), and optionally add | ||
| filescompleter to the positional arguments' add_argument(). | ||
|
|
||
| If things do not work right away: | ||
|
|
||
| - Switch on argcomplete debugging with (also helpful when doing custom | ||
| completers): | ||
| export _ARC_DEBUG=1 | ||
|
|
||
| - Run: | ||
| python-argcomplete-check-easy-install-script $(which appname) | ||
| echo $? | ||
| will echo 0 if the magic line has been found, 1 if not. | ||
|
|
||
| - Sometimes it helps to find early on errors using: | ||
| _ARGCOMPLETE=1 _ARC_DEBUG=1 appname | ||
| which should throw a KeyError: 'COMPLINE' (which is properly set by the | ||
| global argcomplete script). | ||
| """ | ||
|
|
||
| import argparse | ||
| from glob import glob | ||
| import os | ||
| import sys | ||
| from typing import Any | ||
| from typing import List | ||
| from typing import Optional | ||
|
|
||
|
|
||
| class FastFilesCompleter: | ||
| """Fast file completer class.""" | ||
|
|
||
| def __init__(self, directories: bool = True) -> None: | ||
| self.directories = directories | ||
|
|
||
| def __call__(self, prefix: str, **kwargs: Any) -> List[str]: | ||
| # Only called on non option completions. | ||
| if os.sep in prefix[1:]: | ||
| prefix_dir = len(os.path.dirname(prefix) + os.sep) | ||
| else: | ||
| prefix_dir = 0 | ||
| completion = [] | ||
| globbed = [] | ||
| if "*" not in prefix and "?" not in prefix: | ||
| # We are on unix, otherwise no bash. | ||
| if not prefix or prefix[-1] == os.sep: | ||
| globbed.extend(glob(prefix + ".*")) | ||
| prefix += "*" | ||
| globbed.extend(glob(prefix)) | ||
| for x in sorted(globbed): | ||
| if os.path.isdir(x): | ||
| x += "/" | ||
| # Append stripping the prefix (like bash, not like compgen). | ||
| completion.append(x[prefix_dir:]) | ||
| return completion | ||
|
|
||
|
|
||
| if os.environ.get("_ARGCOMPLETE"): | ||
| try: | ||
| import argcomplete.completers | ||
| except ImportError: | ||
| sys.exit(-1) | ||
| filescompleter: Optional[FastFilesCompleter] = FastFilesCompleter() | ||
|
|
||
| def try_argcomplete(parser: argparse.ArgumentParser) -> None: | ||
| argcomplete.autocomplete(parser, always_complete_options=False) | ||
|
|
||
| else: | ||
|
|
||
| def try_argcomplete(parser: argparse.ArgumentParser) -> None: | ||
| pass | ||
|
|
||
| filescompleter = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not commit virtual environment files to version control.
This file is located inside .venv/lib/python3.12/site-packages/, which is a Python virtual environment directory containing installed third-party packages. Virtual environments should never be committed to the repository because:
- They are machine-specific and platform-dependent
- They bloat the repository with thousands of generated files
- They can be regenerated from
requirements.txtorpyproject.toml
Additionally, this file (_pytest/_argcomplete.py) is third-party pytest code, not the time_tracker.py mentioned in the PR description.
Recommended actions:
- Remove the
.venv/directory from this PR and from version control:
git rm -r --cached .venv/- Add
.venv/to your.gitignorefile:
+# Virtual environment
+.venv/
+venv/
+ENV/- Ensure the actual
app/core/time_tracker.pyfile mentioned in the PR description is included in this PR instead.
🧰 Tools
🪛 Ruff (0.14.7)
80-80: Unused method argument: kwargs
(ARG002)
🤖 Prompt for AI Agents
.venv/lib/python3.12/site-packages/_pytest/_argcomplete.py lines 1-117: The
virtual environment and third-party package file were accidentally committed;
remove the .venv directory from the repo, stop tracking it, and update
.gitignore. Run git rm -r --cached .venv/ to unstage and remove the venv from
version control, add an entry for .venv/ to .gitignore (or ensure it exists),
commit those changes, and then add the intended project file
app/core/time_tracker.py to the PR so only your project source (not installed
packages) is included.
| # mypy: allow-untyped-defs | ||
| import ast | ||
| from bisect import bisect_right | ||
| import inspect | ||
| import textwrap | ||
| import tokenize | ||
| import types | ||
| from typing import Iterable | ||
| from typing import Iterator | ||
| from typing import List | ||
| from typing import Optional | ||
| from typing import overload | ||
| from typing import Tuple | ||
| from typing import Union | ||
| import warnings | ||
|
|
||
|
|
||
| class Source: | ||
| """An immutable object holding a source code fragment. | ||
|
|
||
| When using Source(...), the source lines are deindented. | ||
| """ | ||
|
|
||
| def __init__(self, obj: object = None) -> None: | ||
| if not obj: | ||
| self.lines: List[str] = [] | ||
| elif isinstance(obj, Source): | ||
| self.lines = obj.lines | ||
| elif isinstance(obj, (tuple, list)): | ||
| self.lines = deindent(x.rstrip("\n") for x in obj) | ||
| elif isinstance(obj, str): | ||
| self.lines = deindent(obj.split("\n")) | ||
| else: | ||
| try: | ||
| rawcode = getrawcode(obj) | ||
| src = inspect.getsource(rawcode) | ||
| except TypeError: | ||
| src = inspect.getsource(obj) # type: ignore[arg-type] | ||
| self.lines = deindent(src.split("\n")) | ||
|
|
||
| def __eq__(self, other: object) -> bool: | ||
| if not isinstance(other, Source): | ||
| return NotImplemented | ||
| return self.lines == other.lines | ||
|
|
||
| # Ignore type because of https://github.com/python/mypy/issues/4266. | ||
| __hash__ = None # type: ignore | ||
|
|
||
| @overload | ||
| def __getitem__(self, key: int) -> str: ... | ||
|
|
||
| @overload | ||
| def __getitem__(self, key: slice) -> "Source": ... | ||
|
|
||
| def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]: | ||
| if isinstance(key, int): | ||
| return self.lines[key] | ||
| else: | ||
| if key.step not in (None, 1): | ||
| raise IndexError("cannot slice a Source with a step") | ||
| newsource = Source() | ||
| newsource.lines = self.lines[key.start : key.stop] | ||
| return newsource | ||
|
|
||
| def __iter__(self) -> Iterator[str]: | ||
| return iter(self.lines) | ||
|
|
||
| def __len__(self) -> int: | ||
| return len(self.lines) | ||
|
|
||
| def strip(self) -> "Source": | ||
| """Return new Source object with trailing and leading blank lines removed.""" | ||
| start, end = 0, len(self) | ||
| while start < end and not self.lines[start].strip(): | ||
| start += 1 | ||
| while end > start and not self.lines[end - 1].strip(): | ||
| end -= 1 | ||
| source = Source() | ||
| source.lines[:] = self.lines[start:end] | ||
| return source | ||
|
|
||
| def indent(self, indent: str = " " * 4) -> "Source": | ||
| """Return a copy of the source object with all lines indented by the | ||
| given indent-string.""" | ||
| newsource = Source() | ||
| newsource.lines = [(indent + line) for line in self.lines] | ||
| return newsource | ||
|
|
||
| def getstatement(self, lineno: int) -> "Source": | ||
| """Return Source statement which contains the given linenumber | ||
| (counted from 0).""" | ||
| start, end = self.getstatementrange(lineno) | ||
| return self[start:end] | ||
|
|
||
| def getstatementrange(self, lineno: int) -> Tuple[int, int]: | ||
| """Return (start, end) tuple which spans the minimal statement region | ||
| which containing the given lineno.""" | ||
| if not (0 <= lineno < len(self)): | ||
| raise IndexError("lineno out of range") | ||
| ast, start, end = getstatementrange_ast(lineno, self) | ||
| return start, end | ||
|
|
||
| def deindent(self) -> "Source": | ||
| """Return a new Source object deindented.""" | ||
| newsource = Source() | ||
| newsource.lines[:] = deindent(self.lines) | ||
| return newsource | ||
|
|
||
| def __str__(self) -> str: | ||
| return "\n".join(self.lines) | ||
|
|
||
|
|
||
| # | ||
| # helper functions | ||
| # | ||
|
|
||
|
|
||
| def findsource(obj) -> Tuple[Optional[Source], int]: | ||
| try: | ||
| sourcelines, lineno = inspect.findsource(obj) | ||
| except Exception: | ||
| return None, -1 | ||
| source = Source() | ||
| source.lines = [line.rstrip() for line in sourcelines] | ||
| return source, lineno | ||
|
|
||
|
|
||
| def getrawcode(obj: object, trycall: bool = True) -> types.CodeType: | ||
| """Return code object for given function.""" | ||
| try: | ||
| return obj.__code__ # type: ignore[attr-defined,no-any-return] | ||
| except AttributeError: | ||
| pass | ||
| if trycall: | ||
| call = getattr(obj, "__call__", None) | ||
| if call and not isinstance(obj, type): | ||
| return getrawcode(call, trycall=False) | ||
| raise TypeError(f"could not get code object for {obj!r}") | ||
|
|
||
|
|
||
| def deindent(lines: Iterable[str]) -> List[str]: | ||
| return textwrap.dedent("\n".join(lines)).splitlines() | ||
|
|
||
|
|
||
| def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[int]]: | ||
| # Flatten all statements and except handlers into one lineno-list. | ||
| # AST's line numbers start indexing at 1. | ||
| values: List[int] = [] | ||
| for x in ast.walk(node): | ||
| if isinstance(x, (ast.stmt, ast.ExceptHandler)): | ||
| # The lineno points to the class/def, so need to include the decorators. | ||
| if isinstance(x, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)): | ||
| for d in x.decorator_list: | ||
| values.append(d.lineno - 1) | ||
| values.append(x.lineno - 1) | ||
| for name in ("finalbody", "orelse"): | ||
| val: Optional[List[ast.stmt]] = getattr(x, name, None) | ||
| if val: | ||
| # Treat the finally/orelse part as its own statement. | ||
| values.append(val[0].lineno - 1 - 1) | ||
| values.sort() | ||
| insert_index = bisect_right(values, lineno) | ||
| start = values[insert_index - 1] | ||
| if insert_index >= len(values): | ||
| end = None | ||
| else: | ||
| end = values[insert_index] | ||
| return start, end | ||
|
|
||
|
|
||
| def getstatementrange_ast( | ||
| lineno: int, | ||
| source: Source, | ||
| assertion: bool = False, | ||
| astnode: Optional[ast.AST] = None, | ||
| ) -> Tuple[ast.AST, int, int]: | ||
| if astnode is None: | ||
| content = str(source) | ||
| # See #4260: | ||
| # Don't produce duplicate warnings when compiling source to find AST. | ||
| with warnings.catch_warnings(): | ||
| warnings.simplefilter("ignore") | ||
| astnode = ast.parse(content, "source", "exec") | ||
|
|
||
| start, end = get_statement_startend2(lineno, astnode) | ||
| # We need to correct the end: | ||
| # - ast-parsing strips comments | ||
| # - there might be empty lines | ||
| # - we might have lesser indented code blocks at the end | ||
| if end is None: | ||
| end = len(source.lines) | ||
|
|
||
| if end > start + 1: | ||
| # Make sure we don't span differently indented code blocks | ||
| # by using the BlockFinder helper used which inspect.getsource() uses itself. | ||
| block_finder = inspect.BlockFinder() | ||
| # If we start with an indented line, put blockfinder to "started" mode. | ||
| block_finder.started = ( | ||
| bool(source.lines[start]) and source.lines[start][0].isspace() | ||
| ) | ||
| it = ((x + "\n") for x in source.lines[start:end]) | ||
| try: | ||
| for tok in tokenize.generate_tokens(lambda: next(it)): | ||
| block_finder.tokeneater(*tok) | ||
| except (inspect.EndOfBlock, IndentationError): | ||
| end = block_finder.last + start | ||
| except Exception: | ||
| pass | ||
|
|
||
| # The end might still point to a comment or empty line, correct it. | ||
| while end: | ||
| line = source.lines[end - 1].lstrip() | ||
| if line.startswith("#") or not line: | ||
| end -= 1 | ||
| else: | ||
| break | ||
| return astnode, start, end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not commit virtual environment files to the repository.
This file is located inside .venv/, which is the Python virtual environment directory containing installed third-party packages (pytest internals). Virtual environment files should never be committed to version control because:
- They bloat the repository with thousands of files
- They are platform/OS-specific and cause conflicts
- They can be recreated from
requirements.txtorpyproject.toml
Add .venv/ to your .gitignore file and remove these files from the commit:
+# .gitignore
+.venv/
+venv/
+env/
+__pycache__/
+*.pycThen unstage and remove the virtual environment files:
git rm -r --cached .venv/
git commit -m "Remove accidentally committed virtual environment"Additionally, the PR description mentions adding time_tracker.py in app/core/, but that file is not present in this review. Please ensure the correct files are being committed.
🧰 Tools
🪛 Ruff (0.14.7)
60-60: Avoid specifying long messages outside the exception class
(TRY003)
99-99: Avoid specifying long messages outside the exception class
(TRY003)
100-100: Unpacked variable ast is never used
Prefix it with an underscore or any other dummy variable pattern
(RUF059)
121-121: Do not catch blind exception: Exception
(BLE001)
135-135: Using hasattr(x, "__call__") to test if x is callable is unreliable. Use callable(x) for consistent results.
(B004)
138-138: Avoid specifying long messages outside the exception class
(TRY003)
174-174: Unused function argument: assertion
(ARG001)
207-208: try-except-pass detected, consider logging the exception
(S110)
207-207: Do not catch blind exception: Exception
(BLE001)
🤖 Prompt for AI Agents
In .venv/lib/python3.12/site-packages/_pytest/_code/source.py lines 1-217, you
accidentally committed virtual environment files; remove the .venv directory
from the repo by adding ".venv/" to .gitignore, untracking and deleting the
committed venv files from the index (git rm --cached -r .venv) and commit that
change, and then push; also verify the intended file app/core/time_tracker.py is
actually added to the branch and include it in the commit/PR if missing.
| from .terminalwriter import get_terminal_width | ||
| from .terminalwriter import TerminalWriter | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "TerminalWriter", | ||
| "get_terminal_width", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Virtual environment files should not be committed to the repository.
This file is located in .venv/lib/python3.12/site-packages/_pytest/ which is part of the Python virtual environment containing third-party packages. These files should be excluded from version control:
- Add
.venv/to.gitignoreif not already present - Remove all
.venv/files from this PR usinggit rm -r --cached .venv/ - The PR objective mentions creating
time_tracker.pyinapp/core/, but that file is not included in this review
Virtual environment directories are machine-specific, bloat the repository, and should be regenerated via pip install -r requirements.txt on each developer's machine.
🤖 Prompt for AI Agents
.venv/lib/python3.12/site-packages/_pytest/__init__.py lines 1-8: this file is
part of a local virtual environment and must not be committed; fix by adding
.venv/ to .gitignore (if not present), removing the venv files from the repo
history/cache (for example remove the .venv directory from version control),
recommit the change so .venv files are no longer tracked, and ensure the
intended PR changes are present by adding the missing app/core/time_tracker.py
to this branch before pushing.
| # mypy: allow-untyped-defs | ||
| """Report test results in JUnit-XML format, for use with Jenkins and build | ||
| integration servers. | ||
|
|
||
| Based on initial code from Ross Lawley. | ||
|
|
||
| Output conforms to | ||
| https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd | ||
| """ | ||
|
|
||
| from datetime import datetime | ||
| import functools | ||
| import os | ||
| import platform | ||
| import re | ||
| from typing import Callable | ||
| from typing import Dict | ||
| from typing import List | ||
| from typing import Match | ||
| from typing import Optional | ||
| from typing import Tuple | ||
| from typing import Union | ||
| import xml.etree.ElementTree as ET | ||
|
|
||
| from _pytest import nodes | ||
| from _pytest import timing | ||
| from _pytest._code.code import ExceptionRepr | ||
| from _pytest._code.code import ReprFileLocation | ||
| from _pytest.config import Config | ||
| from _pytest.config import filename_arg | ||
| from _pytest.config.argparsing import Parser | ||
| from _pytest.fixtures import FixtureRequest | ||
| from _pytest.reports import TestReport | ||
| from _pytest.stash import StashKey | ||
| from _pytest.terminal import TerminalReporter | ||
| import pytest | ||
|
|
||
|
|
||
| xml_key = StashKey["LogXML"]() | ||
|
|
||
|
|
||
| def bin_xml_escape(arg: object) -> str: | ||
| r"""Visually escape invalid XML characters. | ||
|
|
||
| For example, transforms | ||
| 'hello\aworld\b' | ||
| into | ||
| 'hello#x07world#x08' | ||
| Note that the #xABs are *not* XML escapes - missing the ampersand «. | ||
| The idea is to escape visually for the user rather than for XML itself. | ||
| """ | ||
|
|
||
| def repl(matchobj: Match[str]) -> str: | ||
| i = ord(matchobj.group()) | ||
| if i <= 0xFF: | ||
| return "#x%02X" % i | ||
| else: | ||
| return "#x%04X" % i | ||
|
|
||
| # The spec range of valid chars is: | ||
| # Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] | ||
| # For an unknown(?) reason, we disallow #x7F (DEL) as well. | ||
| illegal_xml_re = ( | ||
| "[^\u0009\u000a\u000d\u0020-\u007e\u0080-\ud7ff\ue000-\ufffd\u10000-\u10ffff]" | ||
| ) | ||
| return re.sub(illegal_xml_re, repl, str(arg)) | ||
|
|
||
|
|
||
| def merge_family(left, right) -> None: | ||
| result = {} | ||
| for kl, vl in left.items(): | ||
| for kr, vr in right.items(): | ||
| if not isinstance(vl, list): | ||
| raise TypeError(type(vl)) | ||
| result[kl] = vl + vr | ||
| left.update(result) | ||
|
|
||
|
|
||
| families = {} | ||
| families["_base"] = {"testcase": ["classname", "name"]} | ||
| families["_base_legacy"] = {"testcase": ["file", "line", "url"]} | ||
|
|
||
| # xUnit 1.x inherits legacy attributes. | ||
| families["xunit1"] = families["_base"].copy() | ||
| merge_family(families["xunit1"], families["_base_legacy"]) | ||
|
|
||
| # xUnit 2.x uses strict base attributes. | ||
| families["xunit2"] = families["_base"] | ||
|
|
||
|
|
||
| class _NodeReporter: | ||
| def __init__(self, nodeid: Union[str, TestReport], xml: "LogXML") -> None: | ||
| self.id = nodeid | ||
| self.xml = xml | ||
| self.add_stats = self.xml.add_stats | ||
| self.family = self.xml.family | ||
| self.duration = 0.0 | ||
| self.properties: List[Tuple[str, str]] = [] | ||
| self.nodes: List[ET.Element] = [] | ||
| self.attrs: Dict[str, str] = {} | ||
|
|
||
| def append(self, node: ET.Element) -> None: | ||
| self.xml.add_stats(node.tag) | ||
| self.nodes.append(node) | ||
|
|
||
| def add_property(self, name: str, value: object) -> None: | ||
| self.properties.append((str(name), bin_xml_escape(value))) | ||
|
|
||
| def add_attribute(self, name: str, value: object) -> None: | ||
| self.attrs[str(name)] = bin_xml_escape(value) | ||
|
|
||
| def make_properties_node(self) -> Optional[ET.Element]: | ||
| """Return a Junit node containing custom properties, if any.""" | ||
| if self.properties: | ||
| properties = ET.Element("properties") | ||
| for name, value in self.properties: | ||
| properties.append(ET.Element("property", name=name, value=value)) | ||
| return properties | ||
| return None | ||
|
|
||
| def record_testreport(self, testreport: TestReport) -> None: | ||
| names = mangle_test_address(testreport.nodeid) | ||
| existing_attrs = self.attrs | ||
| classnames = names[:-1] | ||
| if self.xml.prefix: | ||
| classnames.insert(0, self.xml.prefix) | ||
| attrs: Dict[str, str] = { | ||
| "classname": ".".join(classnames), | ||
| "name": bin_xml_escape(names[-1]), | ||
| "file": testreport.location[0], | ||
| } | ||
| if testreport.location[1] is not None: | ||
| attrs["line"] = str(testreport.location[1]) | ||
| if hasattr(testreport, "url"): | ||
| attrs["url"] = testreport.url | ||
| self.attrs = attrs | ||
| self.attrs.update(existing_attrs) # Restore any user-defined attributes. | ||
|
|
||
| # Preserve legacy testcase behavior. | ||
| if self.family == "xunit1": | ||
| return | ||
|
|
||
| # Filter out attributes not permitted by this test family. | ||
| # Including custom attributes because they are not valid here. | ||
| temp_attrs = {} | ||
| for key in self.attrs: | ||
| if key in families[self.family]["testcase"]: | ||
| temp_attrs[key] = self.attrs[key] | ||
| self.attrs = temp_attrs | ||
|
|
||
| def to_xml(self) -> ET.Element: | ||
| testcase = ET.Element("testcase", self.attrs, time="%.3f" % self.duration) | ||
| properties = self.make_properties_node() | ||
| if properties is not None: | ||
| testcase.append(properties) | ||
| testcase.extend(self.nodes) | ||
| return testcase | ||
|
|
||
| def _add_simple(self, tag: str, message: str, data: Optional[str] = None) -> None: | ||
| node = ET.Element(tag, message=message) | ||
| node.text = bin_xml_escape(data) | ||
| self.append(node) | ||
|
|
||
| def write_captured_output(self, report: TestReport) -> None: | ||
| if not self.xml.log_passing_tests and report.passed: | ||
| return | ||
|
|
||
| content_out = report.capstdout | ||
| content_log = report.caplog | ||
| content_err = report.capstderr | ||
| if self.xml.logging == "no": | ||
| return | ||
| content_all = "" | ||
| if self.xml.logging in ["log", "all"]: | ||
| content_all = self._prepare_content(content_log, " Captured Log ") | ||
| if self.xml.logging in ["system-out", "out-err", "all"]: | ||
| content_all += self._prepare_content(content_out, " Captured Out ") | ||
| self._write_content(report, content_all, "system-out") | ||
| content_all = "" | ||
| if self.xml.logging in ["system-err", "out-err", "all"]: | ||
| content_all += self._prepare_content(content_err, " Captured Err ") | ||
| self._write_content(report, content_all, "system-err") | ||
| content_all = "" | ||
| if content_all: | ||
| self._write_content(report, content_all, "system-out") | ||
|
|
||
| def _prepare_content(self, content: str, header: str) -> str: | ||
| return "\n".join([header.center(80, "-"), content, ""]) | ||
|
|
||
| def _write_content(self, report: TestReport, content: str, jheader: str) -> None: | ||
| tag = ET.Element(jheader) | ||
| tag.text = bin_xml_escape(content) | ||
| self.append(tag) | ||
|
|
||
| def append_pass(self, report: TestReport) -> None: | ||
| self.add_stats("passed") | ||
|
|
||
| def append_failure(self, report: TestReport) -> None: | ||
| # msg = str(report.longrepr.reprtraceback.extraline) | ||
| if hasattr(report, "wasxfail"): | ||
| self._add_simple("skipped", "xfail-marked test passes unexpectedly") | ||
| else: | ||
| assert report.longrepr is not None | ||
| reprcrash: Optional[ReprFileLocation] = getattr( | ||
| report.longrepr, "reprcrash", None | ||
| ) | ||
| if reprcrash is not None: | ||
| message = reprcrash.message | ||
| else: | ||
| message = str(report.longrepr) | ||
| message = bin_xml_escape(message) | ||
| self._add_simple("failure", message, str(report.longrepr)) | ||
|
|
||
| def append_collect_error(self, report: TestReport) -> None: | ||
| # msg = str(report.longrepr.reprtraceback.extraline) | ||
| assert report.longrepr is not None | ||
| self._add_simple("error", "collection failure", str(report.longrepr)) | ||
|
|
||
| def append_collect_skipped(self, report: TestReport) -> None: | ||
| self._add_simple("skipped", "collection skipped", str(report.longrepr)) | ||
|
|
||
| def append_error(self, report: TestReport) -> None: | ||
| assert report.longrepr is not None | ||
| reprcrash: Optional[ReprFileLocation] = getattr( | ||
| report.longrepr, "reprcrash", None | ||
| ) | ||
| if reprcrash is not None: | ||
| reason = reprcrash.message | ||
| else: | ||
| reason = str(report.longrepr) | ||
|
|
||
| if report.when == "teardown": | ||
| msg = f'failed on teardown with "{reason}"' | ||
| else: | ||
| msg = f'failed on setup with "{reason}"' | ||
| self._add_simple("error", bin_xml_escape(msg), str(report.longrepr)) | ||
|
|
||
| def append_skipped(self, report: TestReport) -> None: | ||
| if hasattr(report, "wasxfail"): | ||
| xfailreason = report.wasxfail | ||
| if xfailreason.startswith("reason: "): | ||
| xfailreason = xfailreason[8:] | ||
| xfailreason = bin_xml_escape(xfailreason) | ||
| skipped = ET.Element("skipped", type="pytest.xfail", message=xfailreason) | ||
| self.append(skipped) | ||
| else: | ||
| assert isinstance(report.longrepr, tuple) | ||
| filename, lineno, skipreason = report.longrepr | ||
| if skipreason.startswith("Skipped: "): | ||
| skipreason = skipreason[9:] | ||
| details = f"{filename}:{lineno}: {skipreason}" | ||
|
|
||
| skipped = ET.Element( | ||
| "skipped", type="pytest.skip", message=bin_xml_escape(skipreason) | ||
| ) | ||
| skipped.text = bin_xml_escape(details) | ||
| self.append(skipped) | ||
| self.write_captured_output(report) | ||
|
|
||
| def finalize(self) -> None: | ||
| data = self.to_xml() | ||
| self.__dict__.clear() | ||
| # Type ignored because mypy doesn't like overriding a method. | ||
| # Also the return value doesn't match... | ||
| self.to_xml = lambda: data # type: ignore[method-assign] | ||
|
|
||
|
|
||
| def _warn_incompatibility_with_xunit2( | ||
| request: FixtureRequest, fixture_name: str | ||
| ) -> None: | ||
| """Emit a PytestWarning about the given fixture being incompatible with newer xunit revisions.""" | ||
| from _pytest.warning_types import PytestWarning | ||
|
|
||
| xml = request.config.stash.get(xml_key, None) | ||
| if xml is not None and xml.family not in ("xunit1", "legacy"): | ||
| request.node.warn( | ||
| PytestWarning( | ||
| f"{fixture_name} is incompatible with junit_family '{xml.family}' (use 'legacy' or 'xunit1')" | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def record_property(request: FixtureRequest) -> Callable[[str, object], None]: | ||
| """Add extra properties to the calling test. | ||
|
|
||
| User properties become part of the test report and are available to the | ||
| configured reporters, like JUnit XML. | ||
|
|
||
| The fixture is callable with ``name, value``. The value is automatically | ||
| XML-encoded. | ||
|
|
||
| Example:: | ||
|
|
||
| def test_function(record_property): | ||
| record_property("example_key", 1) | ||
| """ | ||
| _warn_incompatibility_with_xunit2(request, "record_property") | ||
|
|
||
| def append_property(name: str, value: object) -> None: | ||
| request.node.user_properties.append((name, value)) | ||
|
|
||
| return append_property | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def record_xml_attribute(request: FixtureRequest) -> Callable[[str, object], None]: | ||
| """Add extra xml attributes to the tag for the calling test. | ||
|
|
||
| The fixture is callable with ``name, value``. The value is | ||
| automatically XML-encoded. | ||
| """ | ||
| from _pytest.warning_types import PytestExperimentalApiWarning | ||
|
|
||
| request.node.warn( | ||
| PytestExperimentalApiWarning("record_xml_attribute is an experimental feature") | ||
| ) | ||
|
|
||
| _warn_incompatibility_with_xunit2(request, "record_xml_attribute") | ||
|
|
||
| # Declare noop | ||
| def add_attr_noop(name: str, value: object) -> None: | ||
| pass | ||
|
|
||
| attr_func = add_attr_noop | ||
|
|
||
| xml = request.config.stash.get(xml_key, None) | ||
| if xml is not None: | ||
| node_reporter = xml.node_reporter(request.node.nodeid) | ||
| attr_func = node_reporter.add_attribute | ||
|
|
||
| return attr_func | ||
|
|
||
|
|
||
| def _check_record_param_type(param: str, v: str) -> None: | ||
| """Used by record_testsuite_property to check that the given parameter name is of the proper | ||
| type.""" | ||
| __tracebackhide__ = True | ||
| if not isinstance(v, str): | ||
| msg = "{param} parameter needs to be a string, but {g} given" # type: ignore[unreachable] | ||
| raise TypeError(msg.format(param=param, g=type(v).__name__)) | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object], None]: | ||
| """Record a new ``<property>`` tag as child of the root ``<testsuite>``. | ||
|
|
||
| This is suitable to writing global information regarding the entire test | ||
| suite, and is compatible with ``xunit2`` JUnit family. | ||
|
|
||
| This is a ``session``-scoped fixture which is called with ``(name, value)``. Example: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| def test_foo(record_testsuite_property): | ||
| record_testsuite_property("ARCH", "PPC") | ||
| record_testsuite_property("STORAGE_TYPE", "CEPH") | ||
|
|
||
| :param name: | ||
| The property name. | ||
| :param value: | ||
| The property value. Will be converted to a string. | ||
|
|
||
| .. warning:: | ||
|
|
||
| Currently this fixture **does not work** with the | ||
| `pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See | ||
| :issue:`7767` for details. | ||
| """ | ||
| __tracebackhide__ = True | ||
|
|
||
| def record_func(name: str, value: object) -> None: | ||
| """No-op function in case --junit-xml was not passed in the command-line.""" | ||
| __tracebackhide__ = True | ||
| _check_record_param_type("name", name) | ||
|
|
||
| xml = request.config.stash.get(xml_key, None) | ||
| if xml is not None: | ||
| record_func = xml.add_global_property | ||
| return record_func | ||
|
|
||
|
|
||
| def pytest_addoption(parser: Parser) -> None: | ||
| group = parser.getgroup("terminal reporting") | ||
| group.addoption( | ||
| "--junitxml", | ||
| "--junit-xml", | ||
| action="store", | ||
| dest="xmlpath", | ||
| metavar="path", | ||
| type=functools.partial(filename_arg, optname="--junitxml"), | ||
| default=None, | ||
| help="Create junit-xml style report file at given path", | ||
| ) | ||
| group.addoption( | ||
| "--junitprefix", | ||
| "--junit-prefix", | ||
| action="store", | ||
| metavar="str", | ||
| default=None, | ||
| help="Prepend prefix to classnames in junit-xml output", | ||
| ) | ||
| parser.addini( | ||
| "junit_suite_name", "Test suite name for JUnit report", default="pytest" | ||
| ) | ||
| parser.addini( | ||
| "junit_logging", | ||
| "Write captured log messages to JUnit report: " | ||
| "one of no|log|system-out|system-err|out-err|all", | ||
| default="no", | ||
| ) | ||
| parser.addini( | ||
| "junit_log_passing_tests", | ||
| "Capture log information for passing tests to JUnit report: ", | ||
| type="bool", | ||
| default=True, | ||
| ) | ||
| parser.addini( | ||
| "junit_duration_report", | ||
| "Duration time to report: one of total|call", | ||
| default="total", | ||
| ) # choices=['total', 'call']) | ||
| parser.addini( | ||
| "junit_family", | ||
| "Emit XML for schema: one of legacy|xunit1|xunit2", | ||
| default="xunit2", | ||
| ) | ||
|
|
||
|
|
||
| def pytest_configure(config: Config) -> None: | ||
| xmlpath = config.option.xmlpath | ||
| # Prevent opening xmllog on worker nodes (xdist). | ||
| if xmlpath and not hasattr(config, "workerinput"): | ||
| junit_family = config.getini("junit_family") | ||
| config.stash[xml_key] = LogXML( | ||
| xmlpath, | ||
| config.option.junitprefix, | ||
| config.getini("junit_suite_name"), | ||
| config.getini("junit_logging"), | ||
| config.getini("junit_duration_report"), | ||
| junit_family, | ||
| config.getini("junit_log_passing_tests"), | ||
| ) | ||
| config.pluginmanager.register(config.stash[xml_key]) | ||
|
|
||
|
|
||
| def pytest_unconfigure(config: Config) -> None: | ||
| xml = config.stash.get(xml_key, None) | ||
| if xml: | ||
| del config.stash[xml_key] | ||
| config.pluginmanager.unregister(xml) | ||
|
|
||
|
|
||
| def mangle_test_address(address: str) -> List[str]: | ||
| path, possible_open_bracket, params = address.partition("[") | ||
| names = path.split("::") | ||
| # Convert file path to dotted path. | ||
| names[0] = names[0].replace(nodes.SEP, ".") | ||
| names[0] = re.sub(r"\.py$", "", names[0]) | ||
| # Put any params back. | ||
| names[-1] += possible_open_bracket + params | ||
| return names | ||
|
|
||
|
|
||
| class LogXML: | ||
| def __init__( | ||
| self, | ||
| logfile, | ||
| prefix: Optional[str], | ||
| suite_name: str = "pytest", | ||
| logging: str = "no", | ||
| report_duration: str = "total", | ||
| family="xunit1", | ||
| log_passing_tests: bool = True, | ||
| ) -> None: | ||
| logfile = os.path.expanduser(os.path.expandvars(logfile)) | ||
| self.logfile = os.path.normpath(os.path.abspath(logfile)) | ||
| self.prefix = prefix | ||
| self.suite_name = suite_name | ||
| self.logging = logging | ||
| self.log_passing_tests = log_passing_tests | ||
| self.report_duration = report_duration | ||
| self.family = family | ||
| self.stats: Dict[str, int] = dict.fromkeys( | ||
| ["error", "passed", "failure", "skipped"], 0 | ||
| ) | ||
| self.node_reporters: Dict[ | ||
| Tuple[Union[str, TestReport], object], _NodeReporter | ||
| ] = {} | ||
| self.node_reporters_ordered: List[_NodeReporter] = [] | ||
| self.global_properties: List[Tuple[str, str]] = [] | ||
|
|
||
| # List of reports that failed on call but teardown is pending. | ||
| self.open_reports: List[TestReport] = [] | ||
| self.cnt_double_fail_tests = 0 | ||
|
|
||
| # Replaces convenience family with real family. | ||
| if self.family == "legacy": | ||
| self.family = "xunit1" | ||
|
|
||
| def finalize(self, report: TestReport) -> None: | ||
| nodeid = getattr(report, "nodeid", report) | ||
| # Local hack to handle xdist report order. | ||
| workernode = getattr(report, "node", None) | ||
| reporter = self.node_reporters.pop((nodeid, workernode)) | ||
|
|
||
| for propname, propvalue in report.user_properties: | ||
| reporter.add_property(propname, str(propvalue)) | ||
|
|
||
| if reporter is not None: | ||
| reporter.finalize() | ||
|
|
||
| def node_reporter(self, report: Union[TestReport, str]) -> _NodeReporter: | ||
| nodeid: Union[str, TestReport] = getattr(report, "nodeid", report) | ||
| # Local hack to handle xdist report order. | ||
| workernode = getattr(report, "node", None) | ||
|
|
||
| key = nodeid, workernode | ||
|
|
||
| if key in self.node_reporters: | ||
| # TODO: breaks for --dist=each | ||
| return self.node_reporters[key] | ||
|
|
||
| reporter = _NodeReporter(nodeid, self) | ||
|
|
||
| self.node_reporters[key] = reporter | ||
| self.node_reporters_ordered.append(reporter) | ||
|
|
||
| return reporter | ||
|
|
||
| def add_stats(self, key: str) -> None: | ||
| if key in self.stats: | ||
| self.stats[key] += 1 | ||
|
|
||
| def _opentestcase(self, report: TestReport) -> _NodeReporter: | ||
| reporter = self.node_reporter(report) | ||
| reporter.record_testreport(report) | ||
| return reporter | ||
|
|
||
| def pytest_runtest_logreport(self, report: TestReport) -> None: | ||
| """Handle a setup/call/teardown report, generating the appropriate | ||
| XML tags as necessary. | ||
|
|
||
| Note: due to plugins like xdist, this hook may be called in interlaced | ||
| order with reports from other nodes. For example: | ||
|
|
||
| Usual call order: | ||
| -> setup node1 | ||
| -> call node1 | ||
| -> teardown node1 | ||
| -> setup node2 | ||
| -> call node2 | ||
| -> teardown node2 | ||
|
|
||
| Possible call order in xdist: | ||
| -> setup node1 | ||
| -> call node1 | ||
| -> setup node2 | ||
| -> call node2 | ||
| -> teardown node2 | ||
| -> teardown node1 | ||
| """ | ||
| close_report = None | ||
| if report.passed: | ||
| if report.when == "call": # ignore setup/teardown | ||
| reporter = self._opentestcase(report) | ||
| reporter.append_pass(report) | ||
| elif report.failed: | ||
| if report.when == "teardown": | ||
| # The following vars are needed when xdist plugin is used. | ||
| report_wid = getattr(report, "worker_id", None) | ||
| report_ii = getattr(report, "item_index", None) | ||
| close_report = next( | ||
| ( | ||
| rep | ||
| for rep in self.open_reports | ||
| if ( | ||
| rep.nodeid == report.nodeid | ||
| and getattr(rep, "item_index", None) == report_ii | ||
| and getattr(rep, "worker_id", None) == report_wid | ||
| ) | ||
| ), | ||
| None, | ||
| ) | ||
| if close_report: | ||
| # We need to open new testcase in case we have failure in | ||
| # call and error in teardown in order to follow junit | ||
| # schema. | ||
| self.finalize(close_report) | ||
| self.cnt_double_fail_tests += 1 | ||
| reporter = self._opentestcase(report) | ||
| if report.when == "call": | ||
| reporter.append_failure(report) | ||
| self.open_reports.append(report) | ||
| if not self.log_passing_tests: | ||
| reporter.write_captured_output(report) | ||
| else: | ||
| reporter.append_error(report) | ||
| elif report.skipped: | ||
| reporter = self._opentestcase(report) | ||
| reporter.append_skipped(report) | ||
| self.update_testcase_duration(report) | ||
| if report.when == "teardown": | ||
| reporter = self._opentestcase(report) | ||
| reporter.write_captured_output(report) | ||
|
|
||
| self.finalize(report) | ||
| report_wid = getattr(report, "worker_id", None) | ||
| report_ii = getattr(report, "item_index", None) | ||
| close_report = next( | ||
| ( | ||
| rep | ||
| for rep in self.open_reports | ||
| if ( | ||
| rep.nodeid == report.nodeid | ||
| and getattr(rep, "item_index", None) == report_ii | ||
| and getattr(rep, "worker_id", None) == report_wid | ||
| ) | ||
| ), | ||
| None, | ||
| ) | ||
| if close_report: | ||
| self.open_reports.remove(close_report) | ||
|
|
||
| def update_testcase_duration(self, report: TestReport) -> None: | ||
| """Accumulate total duration for nodeid from given report and update | ||
| the Junit.testcase with the new total if already created.""" | ||
| if self.report_duration in {"total", report.when}: | ||
| reporter = self.node_reporter(report) | ||
| reporter.duration += getattr(report, "duration", 0.0) | ||
|
|
||
| def pytest_collectreport(self, report: TestReport) -> None: | ||
| if not report.passed: | ||
| reporter = self._opentestcase(report) | ||
| if report.failed: | ||
| reporter.append_collect_error(report) | ||
| else: | ||
| reporter.append_collect_skipped(report) | ||
|
|
||
| def pytest_internalerror(self, excrepr: ExceptionRepr) -> None: | ||
| reporter = self.node_reporter("internal") | ||
| reporter.attrs.update(classname="pytest", name="internal") | ||
| reporter._add_simple("error", "internal error", str(excrepr)) | ||
|
|
||
| def pytest_sessionstart(self) -> None: | ||
| self.suite_start_time = timing.time() | ||
|
|
||
| def pytest_sessionfinish(self) -> None: | ||
| dirname = os.path.dirname(os.path.abspath(self.logfile)) | ||
| # exist_ok avoids filesystem race conditions between checking path existence and requesting creation | ||
| os.makedirs(dirname, exist_ok=True) | ||
|
|
||
| with open(self.logfile, "w", encoding="utf-8") as logfile: | ||
| suite_stop_time = timing.time() | ||
| suite_time_delta = suite_stop_time - self.suite_start_time | ||
|
|
||
| numtests = ( | ||
| self.stats["passed"] | ||
| + self.stats["failure"] | ||
| + self.stats["skipped"] | ||
| + self.stats["error"] | ||
| - self.cnt_double_fail_tests | ||
| ) | ||
| logfile.write('<?xml version="1.0" encoding="utf-8"?>') | ||
|
|
||
| suite_node = ET.Element( | ||
| "testsuite", | ||
| name=self.suite_name, | ||
| errors=str(self.stats["error"]), | ||
| failures=str(self.stats["failure"]), | ||
| skipped=str(self.stats["skipped"]), | ||
| tests=str(numtests), | ||
| time="%.3f" % suite_time_delta, | ||
| timestamp=datetime.fromtimestamp(self.suite_start_time).isoformat(), | ||
| hostname=platform.node(), | ||
| ) | ||
| global_properties = self._get_global_properties_node() | ||
| if global_properties is not None: | ||
| suite_node.append(global_properties) | ||
| for node_reporter in self.node_reporters_ordered: | ||
| suite_node.append(node_reporter.to_xml()) | ||
| testsuites = ET.Element("testsuites") | ||
| testsuites.append(suite_node) | ||
| logfile.write(ET.tostring(testsuites, encoding="unicode")) | ||
|
|
||
| def pytest_terminal_summary(self, terminalreporter: TerminalReporter) -> None: | ||
| terminalreporter.write_sep("-", f"generated xml file: {self.logfile}") | ||
|
|
||
| def add_global_property(self, name: str, value: object) -> None: | ||
| __tracebackhide__ = True | ||
| _check_record_param_type("name", name) | ||
| self.global_properties.append((name, bin_xml_escape(value))) | ||
|
|
||
| def _get_global_properties_node(self) -> Optional[ET.Element]: | ||
| """Return a Junit node containing custom properties, if any.""" | ||
| if self.global_properties: | ||
| properties = ET.Element("properties") | ||
| for name, value in self.global_properties: | ||
| properties.append(ET.Element("property", name=name, value=value)) | ||
| return properties |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not commit virtual environment files to version control.
This file is part of the pytest package installed in .venv/lib/python3.12/site-packages/. Virtual environment directories should never be committed to a repository because:
- They contain platform-specific binaries that won't work across different OS/architectures
- They massively bloat the repository (often 100+ MB)
- Dependencies should be installed via
pip install -r requirements.txtor similar
Immediate actions required:
-
Remove the
.venv/directory from the repository:git rm -r --cached .venv/
-
Add
.venv/to your.gitignore:+ .venv/ + venv/ + env/ + __pycache__/ + *.pyc
-
Ensure dependencies are documented in
requirements.txtorpyproject.toml
The PR objective mentions creating app/core/time_tracker.py - please ensure only your application code changes are committed, not the entire virtual environment.
🧰 Tools
🪛 Ruff (0.14.7)
72-72: Loop control variable kr not used within loop body
Rename unused kr to _kr
(B007)
190-190: Unused method argument: report
(ARG002)
195-195: Unused method argument: report
(ARG002)
372-372: Unused function argument: value
(ARG001)
🤖 Prompt for AI Agents
.venv/lib/python3.12/site-packages/_pytest/junitxml.py lines 1-700: the PR
accidentally included the project's virtual environment (`.venv`) containing
third-party packages; remove the venv files from the repo, stop tracking them
and ignore them going forward by running git rm -r --cached .venv/ (or remove
the folder and its files if appropriate), add `.venv/` to `.gitignore`, commit
that change, and then re-commit only your intended application files (e.g.
app/core/time_tracker.py); also ensure your dependencies are recorded in
requirements.txt or pyproject.toml so others can recreate the environment.
| # mypy: allow-untyped-defs | ||
| """Add backward compatibility support for the legacy py path type.""" | ||
|
|
||
| import dataclasses | ||
| from pathlib import Path | ||
| import shlex | ||
| import subprocess | ||
| from typing import Final | ||
| from typing import final | ||
| from typing import List | ||
| from typing import Optional | ||
| from typing import TYPE_CHECKING | ||
| from typing import Union | ||
|
|
||
| from iniconfig import SectionWrapper | ||
|
|
||
| from _pytest.cacheprovider import Cache | ||
| from _pytest.compat import LEGACY_PATH | ||
| from _pytest.compat import legacy_path | ||
| from _pytest.config import Config | ||
| from _pytest.config import hookimpl | ||
| from _pytest.config import PytestPluginManager | ||
| from _pytest.deprecated import check_ispytest | ||
| from _pytest.fixtures import fixture | ||
| from _pytest.fixtures import FixtureRequest | ||
| from _pytest.main import Session | ||
| from _pytest.monkeypatch import MonkeyPatch | ||
| from _pytest.nodes import Collector | ||
| from _pytest.nodes import Item | ||
| from _pytest.nodes import Node | ||
| from _pytest.pytester import HookRecorder | ||
| from _pytest.pytester import Pytester | ||
| from _pytest.pytester import RunResult | ||
| from _pytest.terminal import TerminalReporter | ||
| from _pytest.tmpdir import TempPathFactory | ||
|
|
||
|
|
||
| if TYPE_CHECKING: | ||
| import pexpect | ||
|
|
||
|
|
||
| @final | ||
| class Testdir: | ||
| """ | ||
| Similar to :class:`Pytester`, but this class works with legacy legacy_path objects instead. | ||
|
|
||
| All methods just forward to an internal :class:`Pytester` instance, converting results | ||
| to `legacy_path` objects as necessary. | ||
| """ | ||
|
|
||
| __test__ = False | ||
|
|
||
| CLOSE_STDIN: "Final" = Pytester.CLOSE_STDIN | ||
| TimeoutExpired: "Final" = Pytester.TimeoutExpired | ||
|
|
||
| def __init__(self, pytester: Pytester, *, _ispytest: bool = False) -> None: | ||
| check_ispytest(_ispytest) | ||
| self._pytester = pytester | ||
|
|
||
| @property | ||
| def tmpdir(self) -> LEGACY_PATH: | ||
| """Temporary directory where tests are executed.""" | ||
| return legacy_path(self._pytester.path) | ||
|
|
||
| @property | ||
| def test_tmproot(self) -> LEGACY_PATH: | ||
| return legacy_path(self._pytester._test_tmproot) | ||
|
|
||
| @property | ||
| def request(self): | ||
| return self._pytester._request | ||
|
|
||
| @property | ||
| def plugins(self): | ||
| return self._pytester.plugins | ||
|
|
||
| @plugins.setter | ||
| def plugins(self, plugins): | ||
| self._pytester.plugins = plugins | ||
|
|
||
| @property | ||
| def monkeypatch(self) -> MonkeyPatch: | ||
| return self._pytester._monkeypatch | ||
|
|
||
| def make_hook_recorder(self, pluginmanager) -> HookRecorder: | ||
| """See :meth:`Pytester.make_hook_recorder`.""" | ||
| return self._pytester.make_hook_recorder(pluginmanager) | ||
|
|
||
| def chdir(self) -> None: | ||
| """See :meth:`Pytester.chdir`.""" | ||
| return self._pytester.chdir() | ||
|
|
||
| def finalize(self) -> None: | ||
| return self._pytester._finalize() | ||
|
|
||
| def makefile(self, ext, *args, **kwargs) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.makefile`.""" | ||
| if ext and not ext.startswith("."): | ||
| # pytester.makefile is going to throw a ValueError in a way that | ||
| # testdir.makefile did not, because | ||
| # pathlib.Path is stricter suffixes than py.path | ||
| # This ext arguments is likely user error, but since testdir has | ||
| # allowed this, we will prepend "." as a workaround to avoid breaking | ||
| # testdir usage that worked before | ||
| ext = "." + ext | ||
| return legacy_path(self._pytester.makefile(ext, *args, **kwargs)) | ||
|
|
||
| def makeconftest(self, source) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.makeconftest`.""" | ||
| return legacy_path(self._pytester.makeconftest(source)) | ||
|
|
||
| def makeini(self, source) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.makeini`.""" | ||
| return legacy_path(self._pytester.makeini(source)) | ||
|
|
||
| def getinicfg(self, source: str) -> SectionWrapper: | ||
| """See :meth:`Pytester.getinicfg`.""" | ||
| return self._pytester.getinicfg(source) | ||
|
|
||
| def makepyprojecttoml(self, source) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.makepyprojecttoml`.""" | ||
| return legacy_path(self._pytester.makepyprojecttoml(source)) | ||
|
|
||
| def makepyfile(self, *args, **kwargs) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.makepyfile`.""" | ||
| return legacy_path(self._pytester.makepyfile(*args, **kwargs)) | ||
|
|
||
| def maketxtfile(self, *args, **kwargs) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.maketxtfile`.""" | ||
| return legacy_path(self._pytester.maketxtfile(*args, **kwargs)) | ||
|
|
||
| def syspathinsert(self, path=None) -> None: | ||
| """See :meth:`Pytester.syspathinsert`.""" | ||
| return self._pytester.syspathinsert(path) | ||
|
|
||
| def mkdir(self, name) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.mkdir`.""" | ||
| return legacy_path(self._pytester.mkdir(name)) | ||
|
|
||
| def mkpydir(self, name) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.mkpydir`.""" | ||
| return legacy_path(self._pytester.mkpydir(name)) | ||
|
|
||
| def copy_example(self, name=None) -> LEGACY_PATH: | ||
| """See :meth:`Pytester.copy_example`.""" | ||
| return legacy_path(self._pytester.copy_example(name)) | ||
|
|
||
| def getnode(self, config: Config, arg) -> Optional[Union[Item, Collector]]: | ||
| """See :meth:`Pytester.getnode`.""" | ||
| return self._pytester.getnode(config, arg) | ||
|
|
||
| def getpathnode(self, path): | ||
| """See :meth:`Pytester.getpathnode`.""" | ||
| return self._pytester.getpathnode(path) | ||
|
|
||
| def genitems(self, colitems: List[Union[Item, Collector]]) -> List[Item]: | ||
| """See :meth:`Pytester.genitems`.""" | ||
| return self._pytester.genitems(colitems) | ||
|
|
||
| def runitem(self, source): | ||
| """See :meth:`Pytester.runitem`.""" | ||
| return self._pytester.runitem(source) | ||
|
|
||
| def inline_runsource(self, source, *cmdlineargs): | ||
| """See :meth:`Pytester.inline_runsource`.""" | ||
| return self._pytester.inline_runsource(source, *cmdlineargs) | ||
|
|
||
| def inline_genitems(self, *args): | ||
| """See :meth:`Pytester.inline_genitems`.""" | ||
| return self._pytester.inline_genitems(*args) | ||
|
|
||
| def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False): | ||
| """See :meth:`Pytester.inline_run`.""" | ||
| return self._pytester.inline_run( | ||
| *args, plugins=plugins, no_reraise_ctrlc=no_reraise_ctrlc | ||
| ) | ||
|
|
||
| def runpytest_inprocess(self, *args, **kwargs) -> RunResult: | ||
| """See :meth:`Pytester.runpytest_inprocess`.""" | ||
| return self._pytester.runpytest_inprocess(*args, **kwargs) | ||
|
|
||
| def runpytest(self, *args, **kwargs) -> RunResult: | ||
| """See :meth:`Pytester.runpytest`.""" | ||
| return self._pytester.runpytest(*args, **kwargs) | ||
|
|
||
| def parseconfig(self, *args) -> Config: | ||
| """See :meth:`Pytester.parseconfig`.""" | ||
| return self._pytester.parseconfig(*args) | ||
|
|
||
| def parseconfigure(self, *args) -> Config: | ||
| """See :meth:`Pytester.parseconfigure`.""" | ||
| return self._pytester.parseconfigure(*args) | ||
|
|
||
| def getitem(self, source, funcname="test_func"): | ||
| """See :meth:`Pytester.getitem`.""" | ||
| return self._pytester.getitem(source, funcname) | ||
|
|
||
| def getitems(self, source): | ||
| """See :meth:`Pytester.getitems`.""" | ||
| return self._pytester.getitems(source) | ||
|
|
||
| def getmodulecol(self, source, configargs=(), withinit=False): | ||
| """See :meth:`Pytester.getmodulecol`.""" | ||
| return self._pytester.getmodulecol( | ||
| source, configargs=configargs, withinit=withinit | ||
| ) | ||
|
|
||
| def collect_by_name( | ||
| self, modcol: Collector, name: str | ||
| ) -> Optional[Union[Item, Collector]]: | ||
| """See :meth:`Pytester.collect_by_name`.""" | ||
| return self._pytester.collect_by_name(modcol, name) | ||
|
|
||
| def popen( | ||
| self, | ||
| cmdargs, | ||
| stdout=subprocess.PIPE, | ||
| stderr=subprocess.PIPE, | ||
| stdin=CLOSE_STDIN, | ||
| **kw, | ||
| ): | ||
| """See :meth:`Pytester.popen`.""" | ||
| return self._pytester.popen(cmdargs, stdout, stderr, stdin, **kw) | ||
|
|
||
| def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> RunResult: | ||
| """See :meth:`Pytester.run`.""" | ||
| return self._pytester.run(*cmdargs, timeout=timeout, stdin=stdin) | ||
|
|
||
| def runpython(self, script) -> RunResult: | ||
| """See :meth:`Pytester.runpython`.""" | ||
| return self._pytester.runpython(script) | ||
|
|
||
| def runpython_c(self, command): | ||
| """See :meth:`Pytester.runpython_c`.""" | ||
| return self._pytester.runpython_c(command) | ||
|
|
||
| def runpytest_subprocess(self, *args, timeout=None) -> RunResult: | ||
| """See :meth:`Pytester.runpytest_subprocess`.""" | ||
| return self._pytester.runpytest_subprocess(*args, timeout=timeout) | ||
|
|
||
| def spawn_pytest( | ||
| self, string: str, expect_timeout: float = 10.0 | ||
| ) -> "pexpect.spawn": | ||
| """See :meth:`Pytester.spawn_pytest`.""" | ||
| return self._pytester.spawn_pytest(string, expect_timeout=expect_timeout) | ||
|
|
||
| def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn": | ||
| """See :meth:`Pytester.spawn`.""" | ||
| return self._pytester.spawn(cmd, expect_timeout=expect_timeout) | ||
|
|
||
| def __repr__(self) -> str: | ||
| return f"<Testdir {self.tmpdir!r}>" | ||
|
|
||
| def __str__(self) -> str: | ||
| return str(self.tmpdir) | ||
|
|
||
|
|
||
| class LegacyTestdirPlugin: | ||
| @staticmethod | ||
| @fixture | ||
| def testdir(pytester: Pytester) -> Testdir: | ||
| """ | ||
| Identical to :fixture:`pytester`, and provides an instance whose methods return | ||
| legacy ``LEGACY_PATH`` objects instead when applicable. | ||
|
|
||
| New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`. | ||
| """ | ||
| return Testdir(pytester, _ispytest=True) | ||
|
|
||
|
|
||
| @final | ||
| @dataclasses.dataclass | ||
| class TempdirFactory: | ||
| """Backward compatibility wrapper that implements ``py.path.local`` | ||
| for :class:`TempPathFactory`. | ||
|
|
||
| .. note:: | ||
| These days, it is preferred to use ``tmp_path_factory``. | ||
|
|
||
| :ref:`About the tmpdir and tmpdir_factory fixtures<tmpdir and tmpdir_factory>`. | ||
|
|
||
| """ | ||
|
|
||
| _tmppath_factory: TempPathFactory | ||
|
|
||
| def __init__( | ||
| self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False | ||
| ) -> None: | ||
| check_ispytest(_ispytest) | ||
| self._tmppath_factory = tmppath_factory | ||
|
|
||
| def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH: | ||
| """Same as :meth:`TempPathFactory.mktemp`, but returns a ``py.path.local`` object.""" | ||
| return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve()) | ||
|
|
||
| def getbasetemp(self) -> LEGACY_PATH: | ||
| """Same as :meth:`TempPathFactory.getbasetemp`, but returns a ``py.path.local`` object.""" | ||
| return legacy_path(self._tmppath_factory.getbasetemp().resolve()) | ||
|
|
||
|
|
||
| class LegacyTmpdirPlugin: | ||
| @staticmethod | ||
| @fixture(scope="session") | ||
| def tmpdir_factory(request: FixtureRequest) -> TempdirFactory: | ||
| """Return a :class:`pytest.TempdirFactory` instance for the test session.""" | ||
| # Set dynamically by pytest_configure(). | ||
| return request.config._tmpdirhandler # type: ignore | ||
|
|
||
| @staticmethod | ||
| @fixture | ||
| def tmpdir(tmp_path: Path) -> LEGACY_PATH: | ||
| """Return a temporary directory path object which is unique to each test | ||
| function invocation, created as a sub directory of the base temporary | ||
| directory. | ||
|
|
||
| By default, a new base temporary directory is created each test session, | ||
| and old bases are removed after 3 sessions, to aid in debugging. If | ||
| ``--basetemp`` is used then it is cleared each session. See | ||
| :ref:`temporary directory location and retention`. | ||
|
|
||
| The returned object is a `legacy_path`_ object. | ||
|
|
||
| .. note:: | ||
| These days, it is preferred to use ``tmp_path``. | ||
|
|
||
| :ref:`About the tmpdir and tmpdir_factory fixtures<tmpdir and tmpdir_factory>`. | ||
|
|
||
| .. _legacy_path: https://py.readthedocs.io/en/latest/path.html | ||
| """ | ||
| return legacy_path(tmp_path) | ||
|
|
||
|
|
||
| def Cache_makedir(self: Cache, name: str) -> LEGACY_PATH: | ||
| """Return a directory path object with the given name. | ||
|
|
||
| Same as :func:`mkdir`, but returns a legacy py path instance. | ||
| """ | ||
| return legacy_path(self.mkdir(name)) | ||
|
|
||
|
|
||
| def FixtureRequest_fspath(self: FixtureRequest) -> LEGACY_PATH: | ||
| """(deprecated) The file system path of the test module which collected this test.""" | ||
| return legacy_path(self.path) | ||
|
|
||
|
|
||
| def TerminalReporter_startdir(self: TerminalReporter) -> LEGACY_PATH: | ||
| """The directory from which pytest was invoked. | ||
|
|
||
| Prefer to use ``startpath`` which is a :class:`pathlib.Path`. | ||
|
|
||
| :type: LEGACY_PATH | ||
| """ | ||
| return legacy_path(self.startpath) | ||
|
|
||
|
|
||
| def Config_invocation_dir(self: Config) -> LEGACY_PATH: | ||
| """The directory from which pytest was invoked. | ||
|
|
||
| Prefer to use :attr:`invocation_params.dir <InvocationParams.dir>`, | ||
| which is a :class:`pathlib.Path`. | ||
|
|
||
| :type: LEGACY_PATH | ||
| """ | ||
| return legacy_path(str(self.invocation_params.dir)) | ||
|
|
||
|
|
||
| def Config_rootdir(self: Config) -> LEGACY_PATH: | ||
| """The path to the :ref:`rootdir <rootdir>`. | ||
|
|
||
| Prefer to use :attr:`rootpath`, which is a :class:`pathlib.Path`. | ||
|
|
||
| :type: LEGACY_PATH | ||
| """ | ||
| return legacy_path(str(self.rootpath)) | ||
|
|
||
|
|
||
| def Config_inifile(self: Config) -> Optional[LEGACY_PATH]: | ||
| """The path to the :ref:`configfile <configfiles>`. | ||
|
|
||
| Prefer to use :attr:`inipath`, which is a :class:`pathlib.Path`. | ||
|
|
||
| :type: Optional[LEGACY_PATH] | ||
| """ | ||
| return legacy_path(str(self.inipath)) if self.inipath else None | ||
|
|
||
|
|
||
| def Session_stardir(self: Session) -> LEGACY_PATH: | ||
| """The path from which pytest was invoked. | ||
|
|
||
| Prefer to use ``startpath`` which is a :class:`pathlib.Path`. | ||
|
|
||
| :type: LEGACY_PATH | ||
| """ | ||
| return legacy_path(self.startpath) | ||
|
|
||
|
|
||
| def Config__getini_unknown_type( | ||
| self, name: str, type: str, value: Union[str, List[str]] | ||
| ): | ||
| if type == "pathlist": | ||
| # TODO: This assert is probably not valid in all cases. | ||
| assert self.inipath is not None | ||
| dp = self.inipath.parent | ||
| input_values = shlex.split(value) if isinstance(value, str) else value | ||
| return [legacy_path(str(dp / x)) for x in input_values] | ||
| else: | ||
| raise ValueError(f"unknown configuration type: {type}", value) | ||
|
|
||
|
|
||
| def Node_fspath(self: Node) -> LEGACY_PATH: | ||
| """(deprecated) returns a legacy_path copy of self.path""" | ||
| return legacy_path(self.path) | ||
|
|
||
|
|
||
| def Node_fspath_set(self: Node, value: LEGACY_PATH) -> None: | ||
| self.path = Path(value) | ||
|
|
||
|
|
||
| @hookimpl(tryfirst=True) | ||
| def pytest_load_initial_conftests(early_config: Config) -> None: | ||
| """Monkeypatch legacy path attributes in several classes, as early as possible.""" | ||
| mp = MonkeyPatch() | ||
| early_config.add_cleanup(mp.undo) | ||
|
|
||
| # Add Cache.makedir(). | ||
| mp.setattr(Cache, "makedir", Cache_makedir, raising=False) | ||
|
|
||
| # Add FixtureRequest.fspath property. | ||
| mp.setattr(FixtureRequest, "fspath", property(FixtureRequest_fspath), raising=False) | ||
|
|
||
| # Add TerminalReporter.startdir property. | ||
| mp.setattr( | ||
| TerminalReporter, "startdir", property(TerminalReporter_startdir), raising=False | ||
| ) | ||
|
|
||
| # Add Config.{invocation_dir,rootdir,inifile} properties. | ||
| mp.setattr(Config, "invocation_dir", property(Config_invocation_dir), raising=False) | ||
| mp.setattr(Config, "rootdir", property(Config_rootdir), raising=False) | ||
| mp.setattr(Config, "inifile", property(Config_inifile), raising=False) | ||
|
|
||
| # Add Session.startdir property. | ||
| mp.setattr(Session, "startdir", property(Session_stardir), raising=False) | ||
|
|
||
| # Add pathlist configuration type. | ||
| mp.setattr(Config, "_getini_unknown_type", Config__getini_unknown_type) | ||
|
|
||
| # Add Node.fspath property. | ||
| mp.setattr(Node, "fspath", property(Node_fspath, Node_fspath_set), raising=False) | ||
|
|
||
|
|
||
| @hookimpl | ||
| def pytest_configure(config: Config) -> None: | ||
| """Installs the LegacyTmpdirPlugin if the ``tmpdir`` plugin is also installed.""" | ||
| if config.pluginmanager.has_plugin("tmpdir"): | ||
| mp = MonkeyPatch() | ||
| config.add_cleanup(mp.undo) | ||
| # Create TmpdirFactory and attach it to the config object. | ||
| # | ||
| # This is to comply with existing plugins which expect the handler to be | ||
| # available at pytest_configure time, but ideally should be moved entirely | ||
| # to the tmpdir_factory session fixture. | ||
| try: | ||
| tmp_path_factory = config._tmp_path_factory # type: ignore[attr-defined] | ||
| except AttributeError: | ||
| # tmpdir plugin is blocked. | ||
| pass | ||
| else: | ||
| _tmpdirhandler = TempdirFactory(tmp_path_factory, _ispytest=True) | ||
| mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False) | ||
|
|
||
| config.pluginmanager.register(LegacyTmpdirPlugin, "legacypath-tmpdir") | ||
|
|
||
|
|
||
| @hookimpl | ||
| def pytest_plugin_registered(plugin: object, manager: PytestPluginManager) -> None: | ||
| # pytester is not loaded by default and is commonly loaded from a conftest, | ||
| # so checking for it in `pytest_configure` is not enough. | ||
| is_pytester = plugin is manager.get_plugin("pytester") | ||
| if is_pytester and not manager.is_registered(LegacyTestdirPlugin): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if .venv exists and if it's in .gitignore
echo "=== Checking if .venv directory exists ==="
if [ -d .venv ]; then
echo ".venv/ directory exists"
echo "First few files in .venv:"
find .venv -type f -print 2>/dev/null | head -20
else
echo ".venv/ directory does NOT exist in repo root"
fi
echo ""
echo "=== Checking .gitignore ==="
if [ -f .gitignore ]; then
echo "Contents of .gitignore:"
cat .gitignore
else
echo ".gitignore not found"
fi
echo ""
echo "=== Checking git status for .venv ==="
git status .venv 2>&1 || echo "No .venv tracked in git or .venv doesn't exist"
echo ""
echo "=== Checking if file path exists in repo ==="
if [ -f ".venv/lib/python3.12/site-packages/_pytest/legacypath.py" ]; then
echo "File exists at: .venv/lib/python3.12/site-packages/_pytest/legacypath.py"
else
echo "File does NOT exist at: .venv/lib/python3.12/site-packages/_pytest/legacypath.py"
fi
echo ""
echo "=== Listing files in repository root ==="
ls -la | head -20Repository: LumintelAnalytics/ChainReport-API
Length of output: 1667
🏁 Script executed:
#!/bin/bash
# Check if .venv is tracked in git
echo "=== Checking git tracking for .venv ==="
git ls-files .venv 2>/dev/null | head -10
if [ $? -eq 0 ]; then
COUNT=$(git ls-files .venv 2>/dev/null | wc -l)
echo "Total .venv files tracked in git: $COUNT"
else
echo "Error checking git tracking"
fi
echo ""
echo "=== Checking git log for .venv commits ==="
git log --oneline --all -- .venv 2>/dev/null | head -5
if [ $? -ne 0 ] || [ -z "$(git log --oneline --all -- .venv 2>/dev/null)" ]; then
echo "No commits found for .venv/ in git history"
fi
echo ""
echo "=== Checking what this PR review is about ==="
echo "Current git HEAD:"
git log --oneline -1
echo ""
echo "=== Checking if there are any staged changes ==="
git diff --cached --name-only 2>/dev/null
if [ -z "$(git diff --cached --name-only 2>/dev/null)" ]; then
echo "No staged changes found"
fi
echo ""
echo "=== Checking recent git branches/references ==="
git branch -a | head -10
git log --oneline --all | head -10Repository: LumintelAnalytics/ChainReport-API
Length of output: 1564
🏁 Script executed:
#!/bin/bash
# Check if .venv changes are part of the current PR (coderabbit_83 branch)
echo "=== Checking diff between main and coderabbit_83 ==="
git diff main..coderabbit_83 --name-only | grep -c "\.venv" || echo "No .venv files in this PR diff"
echo ""
echo "=== Files changed in this PR ==="
git diff main..coderabbit_83 --name-only | head -20
echo ""
echo "=== Is legacypath.py being modified in this PR? ==="
git diff main..coderabbit_83 -- ".venv/lib/python3.12/site-packages/_pytest/legacypath.py" 2>/dev/null | wc -l
if [ $? -eq 0 ] && [ $(git diff main..coderabbit_83 -- ".venv/lib/python3.12/site-packages/_pytest/legacypath.py" 2>/dev/null | wc -l) -eq 0 ]; then
echo "File is NOT being modified in this PR"
fiRepository: LumintelAnalytics/ChainReport-API
Length of output: 621
Remove 4,855+ virtual environment files from this PR before merging.
This PR adds the entire .venv/ directory (Python virtual environment) to version control, including thousands of third-party package files. This creates critical problems:
- Repository bloat: 4,855+ unnecessary files bloating the repository
- Portability: Platform/architecture-specific binaries break across different environments
- Merge conflicts: Virtual environment changes cause frequent, meaningless conflicts
- Best practice violation: Dependencies belong in
requirements.txtorpyproject.toml, not in git
Required actions:
- Remove all
.venv/files from this PR before committing - Create a
.gitignorefile (if missing) with.venv/to prevent future commits - If
.venv/is already tracked in the repository, it should be removed from git history:
git rm -r --cached .venv/
git commit -m "Remove virtual environment from version control"Users can restore the virtual environment locally by running pip install -r requirements.txt.
🧰 Tools
🪛 Ruff (0.14.7)
398-398: Unused function argument: name
(ARG001)
407-407: Avoid specifying long messages outside the exception class
(TRY003)
🤖 Prompt for AI Agents
In .venv/lib/python3.12/site-packages/_pytest/legacypath.py lines 1-479 the file
is part of a committed virtual environment; remove the entire .venv/ directory
from this PR, add ".venv/" to .gitignore (or update existing .gitignore),
untrack any already committed files with git rm -r --cached .venv/ and commit
that change, and ensure dependencies are represented in requirements.txt or
pyproject.toml so contributors can recreate the venv instead of checking it in.
| SQLAlchemy-2.0.31.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 | ||
| SQLAlchemy-2.0.31.dist-info/LICENSE,sha256=PA9Zq4h9BB3mpOUv_j6e212VIt6Qn66abNettue-MpM,1100 | ||
| SQLAlchemy-2.0.31.dist-info/METADATA,sha256=Fv-yTpqMYGTC6PU1Jc8Ka1Evr74lqaBGNQCG7ALeO3g,9632 | ||
| SQLAlchemy-2.0.31.dist-info/RECORD,, | ||
| SQLAlchemy-2.0.31.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 | ||
| SQLAlchemy-2.0.31.dist-info/WHEEL,sha256=OvtvnbpcaxHa5TgXgfC48E6JA7zLr7svMspPP7Vk5o8,152 | ||
| SQLAlchemy-2.0.31.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11 | ||
| sqlalchemy/__init__.py,sha256=sz89h0rk4HnopZTE-CXiZz3UlVY8JOD-IuYU_8VFqxU,13033 | ||
| sqlalchemy/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/__pycache__/events.cpython-312.pyc,, | ||
| sqlalchemy/__pycache__/exc.cpython-312.pyc,, | ||
| sqlalchemy/__pycache__/inspection.cpython-312.pyc,, | ||
| sqlalchemy/__pycache__/log.cpython-312.pyc,, | ||
| sqlalchemy/__pycache__/schema.cpython-312.pyc,, | ||
| sqlalchemy/__pycache__/types.cpython-312.pyc,, | ||
| sqlalchemy/connectors/__init__.py,sha256=PzXPqZqi3BzEnrs1eW0DcsR4lyknAzhhN9rWcQ97hb4,476 | ||
| sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc,, | ||
| sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc,, | ||
| sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc,, | ||
| sqlalchemy/connectors/aioodbc.py,sha256=GSTiNMO9h0qjPxgqaxDwWZ8HvhWMFNVR6MJQnN1oc40,5288 | ||
| sqlalchemy/connectors/asyncio.py,sha256=K3U5857TD0GmJXIhxgRljKnJhJNzYFhQ8UjyFX0Yyoo,5878 | ||
| sqlalchemy/connectors/pyodbc.py,sha256=t7AjyxIOnaWg3CrlUEpBs4Y5l0HFdNt3P_cSSKhbi0Y,8501 | ||
| sqlalchemy/cyextension/__init__.py,sha256=GzhhN8cjMnDTE0qerlUlpbrNmFPHQWCZ4Gk74OAxl04,244 | ||
| sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/cyextension/collections.cpython-312-x86_64-linux-gnu.so,sha256=yiWEUI6nEQ_I7qykcmoNBCbxIS5efJvVf6Us9OvALGM,1932032 | ||
| sqlalchemy/cyextension/collections.pyx,sha256=L7DZ3DGKpgw2MT2ZZRRxCnrcyE5pU1NAFowWgAzQPEc,12571 | ||
| sqlalchemy/cyextension/immutabledict.cpython-312-x86_64-linux-gnu.so,sha256=s5-ve63GkOH0Ed84oUMd5zUKVBSUubBJGwNEjeKuKvM,805632 | ||
| sqlalchemy/cyextension/immutabledict.pxd,sha256=3x3-rXG5eRQ7bBnktZ-OJ9-6ft8zToPmTDOd92iXpB0,291 | ||
| sqlalchemy/cyextension/immutabledict.pyx,sha256=KfDTYbTfebstE8xuqAtuXsHNAK0_b5q_ymUiinUe_xs,3535 | ||
| sqlalchemy/cyextension/processors.cpython-312-x86_64-linux-gnu.so,sha256=0RbEYS4_mSdRUtsVOCYy8zq6gnI7rJjqaJ8jQPQVLDY,530680 | ||
| sqlalchemy/cyextension/processors.pyx,sha256=R1rHsGLEaGeBq5VeCydjClzYlivERIJ9B-XLOJlf2MQ,1792 | ||
| sqlalchemy/cyextension/resultproxy.cpython-312-x86_64-linux-gnu.so,sha256=sX2NgKKif6tedRM7wlbAl38SbQ771GMLCwPVXxyLQ50,621280 | ||
| sqlalchemy/cyextension/resultproxy.pyx,sha256=eWLdyBXiBy_CLQrF5ScfWJm7X0NeelscSXedtj1zv9Q,2725 | ||
| sqlalchemy/cyextension/util.cpython-312-x86_64-linux-gnu.so,sha256=Ags-M2QyDKaaMNiGZ2rKGxNa5O6G8F0ByiPKTLqjOhI,951048 | ||
| sqlalchemy/cyextension/util.pyx,sha256=B85orxa9LddLuQEaDoVSq1XmAXIbLKxrxpvuB8ogV_o,2530 | ||
| sqlalchemy/dialects/__init__.py,sha256=Kos9Gf5JZg1Vg6GWaCqEbD6e0r1jCwCmcnJIfcxDdcY,1770 | ||
| sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc,, | ||
| sqlalchemy/dialects/_typing.py,sha256=hyv0nKucX2gI8ispB1IsvaUgrEPn9zEcq9hS7kfstEw,888 | ||
| sqlalchemy/dialects/mssql/__init__.py,sha256=r5t8wFRNtBQoiUWh0WfIEWzXZW6f3D0uDt6NZTW_7Cc,1880 | ||
| sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mssql/aioodbc.py,sha256=UQd9ecSMIML713TDnLAviuBVJle7P7i1FtqGZZePk2Y,2022 | ||
| sqlalchemy/dialects/mssql/base.py,sha256=87Z8bQbA8q5_T2Oyd4tUuttWNjYTQD9Dhq-eplDJcY4,132301 | ||
| sqlalchemy/dialects/mssql/information_schema.py,sha256=HswjDc6y0mPXCf_x6VyylHlBdBa4PSY6Evxmmlch700,8084 | ||
| sqlalchemy/dialects/mssql/json.py,sha256=evUACW2O62TAPq8B7QIPagz7jfc664ql9ms68JqiYzg,4816 | ||
| sqlalchemy/dialects/mssql/provision.py,sha256=RTVbgYLFAHzEnpVQDJroU8ji_10MqBTiZfyP9_-QNT4,5362 | ||
| sqlalchemy/dialects/mssql/pymssql.py,sha256=eZRLz7HGt3SdoZUjFBmA9BS43N7AhIASw7VPBPEJuG0,4038 | ||
| sqlalchemy/dialects/mssql/pyodbc.py,sha256=vwM-vBlmRwrqxOc73P0sFOrBSwn24wzc5IkEOpalbXQ,27056 | ||
| sqlalchemy/dialects/mysql/__init__.py,sha256=bxbi4hkysUK2OOVvr1F49akUj1cky27kKb07tgFzI9U,2153 | ||
| sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc,, | ||
| sqlalchemy/dialects/mysql/aiomysql.py,sha256=-oMZnCqNsSki8mlQRTWIwiQPT1OVdZIuANkb90q8LAs,9999 | ||
| sqlalchemy/dialects/mysql/asyncmy.py,sha256=YpuuOh8VknEeqHqUXQGfQ3jhfO3Xb-vZv78Jq5cscJ0,10067 | ||
| sqlalchemy/dialects/mysql/base.py,sha256=KA7tvRxKUw0KwHwMth2rz-NWV0xMkVbYvPoBM9wrAFw,120850 | ||
| sqlalchemy/dialects/mysql/cymysql.py,sha256=eXT1ry0w_qRxjiO24M980c-8PZ9qSsbhqBHntjEiKB0,2300 | ||
| sqlalchemy/dialects/mysql/dml.py,sha256=HXJMAvimJsqvhj3UZO4vW_6LkF5RqaKbHvklAjor7yU,7645 | ||
| sqlalchemy/dialects/mysql/enumerated.py,sha256=ipEPPQqoXfFwcywNdcLlZCEzHBtnitHRah1Gn6nItcg,8448 | ||
| sqlalchemy/dialects/mysql/expression.py,sha256=lsmQCHKwfPezUnt27d2kR6ohk4IRFCA64KBS16kx5dc,4097 | ||
| sqlalchemy/dialects/mysql/json.py,sha256=l6MEZ0qp8FgiRrIQvOMhyEJq0q6OqiEnvDTx5Cbt9uQ,2269 | ||
| sqlalchemy/dialects/mysql/mariadb.py,sha256=kTfBLioLKk4JFFst4TY_iWqPtnvvQXFHknLfm89H2N8,853 | ||
| sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=sRlzRFU5E1512aFyEhmmL1ffeU1u5meaLqtRYTcrH7Y,8568 | ||
| sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=qiQdfLPze3QHuASAZ9iqRzD0hDW8FbKoQnfAEQCF7tM,5675 | ||
| sqlalchemy/dialects/mysql/mysqldb.py,sha256=zPHKMQbHu8bFuD7YvOJewn2axQbfwA93NZoeX3bbbiQ,9502 | ||
| sqlalchemy/dialects/mysql/provision.py,sha256=4oGkClQ8jC3YLPF54sB4kCjFc8HRTwf5zl5zftAAXGo,3474 | ||
| sqlalchemy/dialects/mysql/pymysql.py,sha256=GUnSHd2M2uKjmN46Hheymtm26g7phEgwYOXrX0zLY8M,4083 | ||
| sqlalchemy/dialects/mysql/pyodbc.py,sha256=072crI4qVyPhajYvHnsfFeSrNjLFVPIjBQKo5uyz5yk,4297 | ||
| sqlalchemy/dialects/mysql/reflection.py,sha256=3u34YwT1JJh3uThGZJZ3FKdnUcT7v08QB-tAl1r7VRk,22834 | ||
| sqlalchemy/dialects/mysql/reserved_words.py,sha256=ucKX2p2c3UnMq2ayZuOHuf73eXhu7SKsOsTlIN1Q83I,9258 | ||
| sqlalchemy/dialects/mysql/types.py,sha256=L5cTCsMT1pTedszNEM3jSxFNZEMcHQLprYCZ0vmfsnA,24343 | ||
| sqlalchemy/dialects/oracle/__init__.py,sha256=p4-2gw7TT0bX_MoJXTGD4i8WHctYsK9kCRbkpzykBrc,1493 | ||
| sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc,, | ||
| sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc,, | ||
| sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc,, | ||
| sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc,, | ||
| sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc,, | ||
| sqlalchemy/dialects/oracle/base.py,sha256=-7b5iubFPxJyDRoLXlxj8rk8eBRN2_IdZlB2zzzrrbw,118246 | ||
| sqlalchemy/dialects/oracle/cx_oracle.py,sha256=t5yH4svVz7xoDSITF958blgZ01hbCUEWUKrAXwiCiAE,55566 | ||
| sqlalchemy/dialects/oracle/dictionary.py,sha256=7WMrbPkqo8ZdGjaEZyQr-5f2pajSOF1OTGb8P97z8-g,19519 | ||
| sqlalchemy/dialects/oracle/oracledb.py,sha256=UFcZwrrk0pWfAp_SKJZ1B5rIQHtNhOvuu73_JaSnTbI,9487 | ||
| sqlalchemy/dialects/oracle/provision.py,sha256=O9ZpF4OG6Cx4mMzLRfZwhs8dZjrJETWR402n9c7726A,8304 | ||
| sqlalchemy/dialects/oracle/types.py,sha256=QK3hJvWzKnnCe3oD3rItwEEIwcoBze8qGg7VFOvVlIk,8231 | ||
| sqlalchemy/dialects/postgresql/__init__.py,sha256=wwnNAq4wDQzrlPRzDNB06ayuq3L2HNO99nzeEvq-YcU,3892 | ||
| sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc,, | ||
| sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=7TudtgsPiSB8O5kX8W8KxcNYR8t5h_UHb86b_ChL0P8,5696 | ||
| sqlalchemy/dialects/postgresql/array.py,sha256=bWcame7ntmI_Kx6gmBX0-chwADFdLHeCvaDQ4iX8id8,13734 | ||
| sqlalchemy/dialects/postgresql/asyncpg.py,sha256=nfujNbmAjkVPPt9jhh5ZJp8QziZQJ0fMG4JNnLTdsag,40206 | ||
| sqlalchemy/dialects/postgresql/base.py,sha256=ed49Ode09deJF3jXr8V5sSHTwVoFVq0dlvNdP3mJaBQ,178989 | ||
| sqlalchemy/dialects/postgresql/dml.py,sha256=Pc69Le6qzmUHHb1FT5zeUSD31dWm6SBgdCAGW89cs3s,11212 | ||
| sqlalchemy/dialects/postgresql/ext.py,sha256=1bZ--iNh2O9ym7l2gXZX48yP3yMO4dqb9RpYro2Mj2Q,16262 | ||
| sqlalchemy/dialects/postgresql/hstore.py,sha256=otAx-RTDfpi_tcXkMuQV0JOIXtYgevgnsikLKKOkI6U,11541 | ||
| sqlalchemy/dialects/postgresql/json.py,sha256=9-ZvkLVMfQNSz0aHGml_B8sNg3gVq3-gxLnb5BO7Pog,11217 | ||
| sqlalchemy/dialects/postgresql/named_types.py,sha256=3IV1ufo7zJjKmX4VtGDEnoXE6xEqLJAtGG82IiqHXwY,17594 | ||
| sqlalchemy/dialects/postgresql/operators.py,sha256=NsAaWun_tL3d_be0fs9YL6T4LPKK6crnmFxxIJHgyeY,2808 | ||
| sqlalchemy/dialects/postgresql/pg8000.py,sha256=3yoekiWSF-xnaWMqG76XrYPMqerg-42TdmfsW_ivK9E,18640 | ||
| sqlalchemy/dialects/postgresql/pg_catalog.py,sha256=hY3NXEUHxTWD4umhd2aowNu3laC-61Q_qQ_pReyXTUM,9254 | ||
| sqlalchemy/dialects/postgresql/provision.py,sha256=yqyx-aDFO9l2YcL9f4T5HBP_Lnt5dHsMjpuXUG8mi7A,5762 | ||
| sqlalchemy/dialects/postgresql/psycopg.py,sha256=ACkfuT87vUJEW4kJyUqDYTwlnl5u0FZFlDcvLzxNzFQ,23226 | ||
| sqlalchemy/dialects/postgresql/psycopg2.py,sha256=DbCB1-90O8YQDaIR67RtKOjzW3nvrdHoiwnVWYv_mX4,31605 | ||
| sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=M7wAYSL6Pvt-4nbfacAHGyyw4XMKJ_bQZ1tc1pBtIdg,1756 | ||
| sqlalchemy/dialects/postgresql/ranges.py,sha256=6CgV7qkxEMJ9AQsiibo_XBLJYzGh-2ZxpG83sRaesVY,32949 | ||
| sqlalchemy/dialects/postgresql/types.py,sha256=Jfxqw9JaKNOq29JRWBublywgb3lLMyzx8YZI7CXpS2s,7300 | ||
| sqlalchemy/dialects/sqlite/__init__.py,sha256=lp9DIggNn349M-7IYhUA8et8--e8FRExWD2V_r1LJk4,1182 | ||
| sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc,, | ||
| sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=g3qGV6jmiXabWyb3282g_Nmxtj1jThxGSe9C9yalb-U,12345 | ||
| sqlalchemy/dialects/sqlite/base.py,sha256=lUtigjn7NdPBq831zQsLcBwdwRJqdgKM_tUaDrMElOE,96794 | ||
| sqlalchemy/dialects/sqlite/dml.py,sha256=9GE55WvwoktKy2fHeT-Wbc9xPHgsbh5oBfd_fckMH5Q,8443 | ||
| sqlalchemy/dialects/sqlite/json.py,sha256=Eoplbb_4dYlfrtmQaI8Xddd2suAIHA-IdbDQYM-LIhs,2777 | ||
| sqlalchemy/dialects/sqlite/provision.py,sha256=UCpmwxf4IWlrpb2eLHGbPTpCFVbdI_KAh2mKtjiLYao,5632 | ||
| sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=OL2S_05DK9kllZj6DOz7QtEl7jI7syxjW6woS725ii4,5356 | ||
| sqlalchemy/dialects/sqlite/pysqlite.py,sha256=USPhTjA19ks7VfzjlMXN_BkUpZiPH8J5ZyR4B9DBhVY,28045 | ||
| sqlalchemy/dialects/type_migration_guidelines.txt,sha256=-uHNdmYFGB7bzUNT6i8M5nb4j6j9YUKAtW4lcBZqsMg,8239 | ||
| sqlalchemy/engine/__init__.py,sha256=Stb2oV6l8w65JvqEo6J4qtKoApcmOpXy3AAxQud4C1o,2818 | ||
| sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/create.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/default.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/events.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/mock.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/processors.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/result.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/row.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/url.cpython-312.pyc,, | ||
| sqlalchemy/engine/__pycache__/util.cpython-312.pyc,, | ||
| sqlalchemy/engine/_py_processors.py,sha256=j9i_lcYYQOYJMcsDerPxI0sVFBIlX5sqoYMdMJlgWPI,3744 | ||
| sqlalchemy/engine/_py_row.py,sha256=wSqoUFzLOJ1f89kgDb6sJm9LUrF5LMFpXPcK1vUsKcs,3787 | ||
| sqlalchemy/engine/_py_util.py,sha256=f2DI3AN1kv6EplelowesCVpwS8hSXNufRkZoQmJtSH8,2484 | ||
| sqlalchemy/engine/base.py,sha256=0jDuJYb1tipD-N9chnMCvd25JySJQCm8CDCt_lobmv0,122898 | ||
| sqlalchemy/engine/characteristics.py,sha256=N3kbvw_ApMh86wb5yAGnxtPYD4YRhYMWion1H_aVZBI,4765 | ||
| sqlalchemy/engine/create.py,sha256=mYJtOG2ZKM8sgyfjpGpamW15RDU7JXi5s6iibbJHMIs,33206 | ||
| sqlalchemy/engine/cursor.py,sha256=cFq61yrw76k-QR_xNUBWuL-Zeyb14ltG-6jo2Q2iuuw,76392 | ||
| sqlalchemy/engine/default.py,sha256=B3i9Ce3Jk64CtNaS1gnes4uCMhiQn2cMwnZh5RxR-aE,84137 | ||
| sqlalchemy/engine/events.py,sha256=c0unNFFiHzTAvkUtXoJaxzMFMDwurBkHiiUhuN8qluc,37381 | ||
| sqlalchemy/engine/interfaces.py,sha256=n6G7VW5kaGyBlKdCkgaDs694tfzLPOxZeboDmVaJThg,112832 | ||
| sqlalchemy/engine/mock.py,sha256=yvpxgFmRw5G4QsHeF-ZwQGHKES-HqQOucTxFtN1uzdk,4179 | ||
| sqlalchemy/engine/processors.py,sha256=XyfINKbo-2fjN-mW55YybvFyQMOil50_kVqsunahkNs,2379 | ||
| sqlalchemy/engine/reflection.py,sha256=FlT5kPpKm7Lah50GNt5XcnlJWojTL3LD_x0SoCF9kfY,75127 | ||
| sqlalchemy/engine/result.py,sha256=j6BI4Wj2bziQNQG5OlG_Cm4KcNWY9AoYvTXVlJUU-D8,77603 | ||
| sqlalchemy/engine/row.py,sha256=9AAQo9zYDL88GcZ3bjcQTwMT-YIcuGTSMAyTfmBJ_yM,12032 | ||
| sqlalchemy/engine/strategies.py,sha256=DqFSWaXJPL-29Omot9O0aOcuGL8KmCGyOvnPGDkAJoE,442 | ||
| sqlalchemy/engine/url.py,sha256=8eWkUaIUyDExOcJ2D4xJXRcn4OY1GQJ3Q2duSX6UGAg,30784 | ||
| sqlalchemy/engine/util.py,sha256=bNirO8k1S8yOW61uNH-a9QrWtAJ9VGFgbiR0lk1lUQU,5682 | ||
| sqlalchemy/event/__init__.py,sha256=KBrp622xojnC3FFquxa2JsMamwAbfkvzfv6Op0NKiYc,997 | ||
| sqlalchemy/event/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/event/__pycache__/api.cpython-312.pyc,, | ||
| sqlalchemy/event/__pycache__/attr.cpython-312.pyc,, | ||
| sqlalchemy/event/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/event/__pycache__/legacy.cpython-312.pyc,, | ||
| sqlalchemy/event/__pycache__/registry.cpython-312.pyc,, | ||
| sqlalchemy/event/api.py,sha256=DtDVgjKSorOfp9MGJ7fgMWrj4seC_hkwF4D8CW1RFZU,8226 | ||
| sqlalchemy/event/attr.py,sha256=X8QeHGK4ioSYht1vkhc11f606_mq_t91jMNIT314ubs,20751 | ||
| sqlalchemy/event/base.py,sha256=XeNX-y2X2rYZqxNEnylx-_UUTYpVc4TWjLWIGjx4Jkc,15161 | ||
| sqlalchemy/event/legacy.py,sha256=teMPs00fO-4g8a_z2omcVKkYce5wj_1uvJO2n2MIeuo,8227 | ||
| sqlalchemy/event/registry.py,sha256=nfTSSyhjZZXc5wseWB4sXn-YibSc0LKX8mg17XlWmAo,10835 | ||
| sqlalchemy/events.py,sha256=k-ZD38aSPD29LYhED7CBqttp5MDVVx_YSaWC2-cu9ec,525 | ||
| sqlalchemy/exc.py,sha256=M_8-O1hd8i6gbyx-TapV400p_Lxq2QqTGMXUAO-YgCc,23976 | ||
| sqlalchemy/ext/__init__.py,sha256=S1fGKAbycnQDV01gs-JWGaFQ9GCD4QHwKcU2wnugg_o,322 | ||
| sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/automap.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/baked.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc,, | ||
| sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc,, | ||
| sqlalchemy/ext/associationproxy.py,sha256=5O5ANHARO8jytvqBQmOu-QjNVE4Hh3tfYquqKAj5ajs,65771 | ||
| sqlalchemy/ext/asyncio/__init__.py,sha256=1OqSxEyIUn7RWLGyO12F-jAUIvk1I6DXlVy80-Gvkds,1317 | ||
| sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc,, | ||
| sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc,, | ||
| sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc,, | ||
| sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc,, | ||
| sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc,, | ||
| sqlalchemy/ext/asyncio/base.py,sha256=fl7wxZD9KjgFiCtG3WXrYjHEvanamcsodCqq9pH9lOk,8905 | ||
| sqlalchemy/ext/asyncio/engine.py,sha256=S_IRWX4QAjj2veLSu4Y3gKBIXkKQt7_2StJAK2_KUDY,48190 | ||
| sqlalchemy/ext/asyncio/exc.py,sha256=8sII7VMXzs2TrhizhFQMzSfcroRtiesq8o3UwLfXSgQ,639 | ||
| sqlalchemy/ext/asyncio/result.py,sha256=ID2eh-NHW-lnNFTxbKhje8fr-tnsucUsiw_jcpGcSPc,30409 | ||
| sqlalchemy/ext/asyncio/scoping.py,sha256=UxHAFxtWKqA7TEozyN2h7MJyzSspTCrS-1SlgQLTExo,52608 | ||
| sqlalchemy/ext/asyncio/session.py,sha256=mkFFC1C2mPuopz3BwkfSVTlp3vuIDc8hxiQx5ky5rvc,63103 | ||
| sqlalchemy/ext/automap.py,sha256=cMs3mMXZBbfQXahxHbT3-6h5uMM--GZIcdtwhRrZoio,61589 | ||
| sqlalchemy/ext/baked.py,sha256=H6T1il7GY84BhzPFj49UECSpZh_eBuiHomA-QIsYOYQ,17807 | ||
| sqlalchemy/ext/compiler.py,sha256=ONPoxoKD2yUS9R2-oOhmPsA7efm-Bs0BXo7HE1dGlsU,20391 | ||
| sqlalchemy/ext/declarative/__init__.py,sha256=20psLdFQbbOWfpdXHZ0CTY6I1k4UqXvKemNVu1LvPOI,1818 | ||
| sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc,, | ||
| sqlalchemy/ext/declarative/extensions.py,sha256=uCjN1GisQt54AjqYnKYzJdUjnGd2pZBW47WWdPlS7FE,19547 | ||
| sqlalchemy/ext/horizontal_shard.py,sha256=wuwAPnHymln0unSBnyx-cpX0AfESKSsypaSQTYCvzDk,16750 | ||
| sqlalchemy/ext/hybrid.py,sha256=IYkCaPZ29gm2cPKPg0cWMkLCEqMykD8-JJTvgacGbmc,52458 | ||
| sqlalchemy/ext/indexable.py,sha256=UkTelbydKCdKelzbv3HWFFavoET9WocKaGRPGEOVfN8,11032 | ||
| sqlalchemy/ext/instrumentation.py,sha256=sg8ghDjdHSODFXh_jAmpgemnNX1rxCeeXEG3-PMdrNk,15707 | ||
| sqlalchemy/ext/mutable.py,sha256=L5ZkHBGYhMaqO75Xtyrk2DBR44RDk0g6Rz2HzHH0F8Q,37355 | ||
| sqlalchemy/ext/mypy/__init__.py,sha256=0WebDIZmqBD0OTq5JLtd_PmfF9JGxe4d4Qv3Ml3PKUg,241 | ||
| sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc,, | ||
| sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc,, | ||
| sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc,, | ||
| sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc,, | ||
| sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc,, | ||
| sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc,, | ||
| sqlalchemy/ext/mypy/apply.py,sha256=Aek_-XA1eXihT4attxhfE43yBKtCgsxBSb--qgZKUqc,10550 | ||
| sqlalchemy/ext/mypy/decl_class.py,sha256=1vVJRII2apnLTUbc5HkJS6Z2GueaUv_eKvhbqh7Wik4,17384 | ||
| sqlalchemy/ext/mypy/infer.py,sha256=KVnmLFEVS33Al8pUKI7MJbJQu3KeveBUMl78EluBORw,19369 | ||
| sqlalchemy/ext/mypy/names.py,sha256=Q3ef8XQBgVm9WUwlItqlYCXDNi_kbV5DdLEgbtEMEI8,10479 | ||
| sqlalchemy/ext/mypy/plugin.py,sha256=74ML8LI9xar0V86oCxnPFv5FQGEEfUzK64vOay4BKFs,9750 | ||
| sqlalchemy/ext/mypy/util.py,sha256=1zuDQG8ezmF-XhJmAQU_lcBHiD--sL-lq20clg8t4lE,9448 | ||
| sqlalchemy/ext/orderinglist.py,sha256=TGYbsGH72wEZcFNQDYDsZg9OSPuzf__P8YX8_2HtYUo,14384 | ||
| sqlalchemy/ext/serializer.py,sha256=D0g4jMZkRk0Gjr0L-FZe81SR63h0Zs-9JzuWtT_SD7k,6140 | ||
| sqlalchemy/future/__init__.py,sha256=q2mw-gxk_xoxJLEvRoyMha3vO1xSRHrslcExOHZwmPA,512 | ||
| sqlalchemy/future/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/future/__pycache__/engine.cpython-312.pyc,, | ||
| sqlalchemy/future/engine.py,sha256=AgIw6vMsef8W6tynOTkxsjd6o_OQDwGjLdbpoMD8ue8,495 | ||
| sqlalchemy/inspection.py,sha256=MF-LE358wZDUEl1IH8-Uwt2HI65EsQpQW5o5udHkZwA,5063 | ||
| sqlalchemy/log.py,sha256=8x9UR3nj0uFm6or6bQF-JWb4fYv2zOeQjG_w-0wOJFA,8607 | ||
| sqlalchemy/orm/__init__.py,sha256=ZYys5nL3RFUDCMOLFDBrRI52F6er3S1U1OY9TeORuKs,8463 | ||
| sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/collections.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/context.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/events.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/exc.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/identity.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/loading.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/properties.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/query.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/session.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/state.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/sync.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/util.cpython-312.pyc,, | ||
| sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc,, | ||
| sqlalchemy/orm/_orm_constructors.py,sha256=lVn8IZzU_Yq88you3qC8cnm4D1V9Wsf_LeEVTMX-QGc,100158 | ||
| sqlalchemy/orm/_typing.py,sha256=DVBfpHmDVK4x1zxaGJPY2GoTrAsyR6uexv20Lzf1afc,4973 | ||
| sqlalchemy/orm/attributes.py,sha256=wGpyY9aIxWRkL3y6qlbUgIW78rGA4X38ZhOaWI9S818,92535 | ||
| sqlalchemy/orm/base.py,sha256=re6A8ooMxLyfCAeQfhBwwxeJQkiH7EtzzOZIVIiTPlw,27466 | ||
| sqlalchemy/orm/bulk_persistence.py,sha256=wU204OQK-V6rJfpc3HPeMAA1X9vZg9nSNpI1zKuZtcY,70086 | ||
| sqlalchemy/orm/clsregistry.py,sha256=29LyYiuj0qbebOpgW6DbBPNB2ikTweFQar1byCst7I0,17958 | ||
| sqlalchemy/orm/collections.py,sha256=jpMsJGVixmrW9kfT8wevm9kpatKRqyDLcqWd7CjKPxE,52179 | ||
| sqlalchemy/orm/context.py,sha256=pFFc-1ZjaV3aQMAO27UIh0W6NyLc30n2IbuWNprMtS8,112445 | ||
| sqlalchemy/orm/decl_api.py,sha256=_WPKQ_vSE5k2TLtNmkaxxYmvbhZvkRMrrvCeDxdqDQE,63998 | ||
| sqlalchemy/orm/decl_base.py,sha256=oeL7xrty2J81FyDx03dNe02BtZ-R6iYpum-BoA1rhik,82822 | ||
| sqlalchemy/orm/dependency.py,sha256=hgjksUWhgbmgHK5GdJdiDCBgDAIGQXIrY-Tj79tbL2k,47631 | ||
| sqlalchemy/orm/descriptor_props.py,sha256=pKtpP7H1LB_YuHRVrEYpfFZybEnUUdPwQXxduYFe2hA,37180 | ||
| sqlalchemy/orm/dynamic.py,sha256=jksBDCOsm6EBMVParcNGuMeaAv12hX4IzouKspC-HPA,9786 | ||
| sqlalchemy/orm/evaluator.py,sha256=q292K5vdpP69G7Z9y1RqI5GFAk2diUPwnsXE8De_Wgw,11925 | ||
| sqlalchemy/orm/events.py,sha256=0lxP-EluVWSUr07ny2nsuQ8QhrDu9Qc4ON6QRUhuJnA,127703 | ||
| sqlalchemy/orm/exc.py,sha256=IP40P-wOeXhkYk0YizuTC3wqm6W9cPTaQU08f5MMaQ0,7413 | ||
| sqlalchemy/orm/identity.py,sha256=jHdCxCpCyda_8mFOfGmN_Pr0XZdKiU-2hFZshlNxbHs,9249 | ||
| sqlalchemy/orm/instrumentation.py,sha256=M-kZmkUvHUxtf-0mCA8RIM5QmMH1hWlYR_pKMwaidjA,24321 | ||
| sqlalchemy/orm/interfaces.py,sha256=Hmf1BjbfOarZRgMlruqghR7cgH2xyugA9v5t0x-a-wU,48502 | ||
| sqlalchemy/orm/loading.py,sha256=9RacpzFOWbuKgPRWHFmyIvD4fYCLAnkpwBFASyQ2CoI,58277 | ||
| sqlalchemy/orm/mapped_collection.py,sha256=3cneB1dfPTLrsTvKoo9_oCY2xtq4UAHfe5WSXPyqIS4,19690 | ||
| sqlalchemy/orm/mapper.py,sha256=bfoRzNKKnjF-CDvr2Df7HZC9TepvtuQ49LRz_fW7DGQ,171088 | ||
| sqlalchemy/orm/path_registry.py,sha256=sJZMv_WPqUpHfQtKWaX3WYFeKBcNJ8C3wOM2mkBGkTE,25920 | ||
| sqlalchemy/orm/persistence.py,sha256=dzyB2JOXNwQgaCbN8kh0sEz00WFePr48qf8NWVCUZH8,61701 | ||
| sqlalchemy/orm/properties.py,sha256=eDPFzxYUgdM3uWjHywnb1XW-i0tVKKyx7A2MCD31GQU,29306 | ||
| sqlalchemy/orm/query.py,sha256=qKuFTUlbGVjs84AQ7APBY0PJhrzc2JJ1upeI658MV_o,117596 | ||
| sqlalchemy/orm/relationships.py,sha256=dS5SY0v1MiD7iCNnAQlHaI6prUQhL5EkXT7ijc8FR8E,128644 | ||
| sqlalchemy/orm/scoping.py,sha256=rJVc7_Lic4V00HZ-UvYFWkVpXqdrMayRmIs4fIwH1UA,78688 | ||
| sqlalchemy/orm/session.py,sha256=aBBbHL08H-diS6UxGbySgitga6FCRWdN-EcpP3tPC4M,195261 | ||
| sqlalchemy/orm/state.py,sha256=327-F4TG29s6mLC8oWRiO2PuvYIUZzY1MqUPjtUy7M4,37670 | ||
| sqlalchemy/orm/state_changes.py,sha256=qKYg7NxwrDkuUY3EPygAztym6oAVUFcP2wXn7QD3Mz4,6815 | ||
| sqlalchemy/orm/strategies.py,sha256=3fYRUlO61WKgxH2ZSn1kwkJyTRHZk7b9vlfCR4i1kXY,114994 | ||
| sqlalchemy/orm/strategy_options.py,sha256=-n44NV8QX-3uWjhFMA_R_7vYy-d57gJY9snB9JeOj-w,85341 | ||
| sqlalchemy/orm/sync.py,sha256=g7iZfSge1HgxMk9SKRgUgtHEbpbZ1kP_CBqOIdTOXqc,5779 | ||
| sqlalchemy/orm/unitofwork.py,sha256=fiVaqcymbDDHRa1NjS90N9Z466nd5pkJOEi1dHO6QLY,27033 | ||
| sqlalchemy/orm/util.py,sha256=JdroiJ788zPjrNdLYae_bj0hsxzEDJjLbpUMwqonLCU,80728 | ||
| sqlalchemy/orm/writeonly.py,sha256=SYu2sAaHZONk2pW4PmtE871LG-O0P_bjidvKzY1H_zI,22305 | ||
| sqlalchemy/pool/__init__.py,sha256=qiDdq4r4FFAoDrK6ncugF_i6usi_X1LeJt-CuBHey0s,1804 | ||
| sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/pool/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/pool/__pycache__/events.cpython-312.pyc,, | ||
| sqlalchemy/pool/__pycache__/impl.cpython-312.pyc,, | ||
| sqlalchemy/pool/base.py,sha256=WF4az4ZKuzQGuKeSJeyexaYjmWZUvYdC6KIi8zTGodw,52236 | ||
| sqlalchemy/pool/events.py,sha256=xGjkIUZl490ZDtCHqnQF9ZCwe2Jv93eGXmnQxftB11E,13147 | ||
| sqlalchemy/pool/impl.py,sha256=JwpALSkH-pCoO_6oENbkHYY00Jx9nlttyoI61LivRNc,18944 | ||
| sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 | ||
| sqlalchemy/schema.py,sha256=dKiWmgHYjcKQ4TiiD6vD0UMmIsD8u0Fsor1M9AAeGUs,3194 | ||
| sqlalchemy/sql/__init__.py,sha256=UNa9EUiYWoPayf-FzNcwVgQvpsBdInPZfpJesAStN9o,5820 | ||
| sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/crud.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/dml.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/elements.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/events.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/expression.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/functions.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/naming.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/operators.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/roles.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/schema.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/util.cpython-312.pyc,, | ||
| sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc,, | ||
| sqlalchemy/sql/_dml_constructors.py,sha256=YdBJex0MCVACv4q2nl_ii3uhxzwU6aDB8zAsratX5UQ,3867 | ||
| sqlalchemy/sql/_elements_constructors.py,sha256=1SX6o1ezeB8C9DAa2m0WxmfhM3ji3FeCprXFQkNerNY,63048 | ||
| sqlalchemy/sql/_orm_types.py,sha256=T-vjcry4C1y0GToFKVxQCnmly_-Zsq4IO4SHN6bvUF4,625 | ||
| sqlalchemy/sql/_py_util.py,sha256=hiM9ePbRSGs60bAMxPFuJCIC_p9SQ1VzqXGiPchiYwE,2173 | ||
| sqlalchemy/sql/_selectable_constructors.py,sha256=wjE6HrLm9cR7bxvZXT8sFLUqT6t_J9G1XyQCnYmBDl0,18780 | ||
| sqlalchemy/sql/_typing.py,sha256=oqwrYHVMtK-AuKGH9c4SgfiOEJUt5vjkzSEzzscMHkM,12771 | ||
| sqlalchemy/sql/annotation.py,sha256=aqbbVz9kfbCT3_66CZ9GEirVN197Cukoqt8rq48FgkQ,18245 | ||
| sqlalchemy/sql/base.py,sha256=Lg7iHywXmB7XuRMar45XSM4KayChGhfj1c8E7nWUJdo,73899 | ||
| sqlalchemy/sql/cache_key.py,sha256=0Db8mR8IrpBgdzXs4TGTt98LOpL3c7KABd72MAPKUQQ,33668 | ||
| sqlalchemy/sql/coercions.py,sha256=1xzN_9U5BCJGgokdc5iYj5o2cMAfEEZkr1Oa9Q-JYj8,40493 | ||
| sqlalchemy/sql/compiler.py,sha256=e5XWUmeZnE3O8r7fndfmXjAze3qlFZY223BHqrso0AY,274647 | ||
| sqlalchemy/sql/crud.py,sha256=g9xcol2KRGjZi1qsb2-bVz8zgVy_53gfMtJcnNO2vyQ,56521 | ||
| sqlalchemy/sql/ddl.py,sha256=CIqMilCKfuQnF0lrZsQdTxgrbXqcTauKr0Ojzj77PFQ,45602 | ||
| sqlalchemy/sql/default_comparator.py,sha256=utXWsZVGEjflhFfCT4ywa6RnhORc1Rryo87Hga71Rps,16707 | ||
| sqlalchemy/sql/dml.py,sha256=pn0Lm1ofC5qVZzwGWFW73lPCiNba8OsTeemurJgwRyg,65614 | ||
| sqlalchemy/sql/elements.py,sha256=XpfBuu4sh5W5lHHUZN95DTl4FM4MM_zs0GKqHZvdXXM,176146 | ||
| sqlalchemy/sql/events.py,sha256=iC_Q1Htm1Aobt5tOYxWfHHqNpoytrULORmUKcusH_-E,18290 | ||
| sqlalchemy/sql/expression.py,sha256=VMX-dLpsZYnVRJpYNDozDUgaj7iQ0HuewUKVefD57PE,7586 | ||
| sqlalchemy/sql/functions.py,sha256=kMMYplvuIHFAPwxBI03SizwaLcYEHzysecWk-R1V-JM,63762 | ||
| sqlalchemy/sql/lambdas.py,sha256=DP0Qz7Ypo8QhzMwygGHYgRhwJMx-rNezO1euouH3iYU,49292 | ||
| sqlalchemy/sql/naming.py,sha256=ZHs1qSV3ou8TYmZ92uvU3sfdklUQlIz4uhe330n05SU,6858 | ||
| sqlalchemy/sql/operators.py,sha256=r4oQp4h5zTMFFOpiFNV56joIK-QIjJCobatsmaZ-724,75935 | ||
| sqlalchemy/sql/roles.py,sha256=pOsVn_OZD7mF2gJByHf24Rjopt0_Hu3dUCEOK5t4KS8,7662 | ||
| sqlalchemy/sql/schema.py,sha256=-5QrCcIJNbs1Et6oRzfpTDvhP4R3KbRJkGiYuJExayI,229767 | ||
| sqlalchemy/sql/selectable.py,sha256=gAOLh2hq0xRVqAaO6ctQr9cgLgdz40iCEhCJ_Gp49cE,233587 | ||
| sqlalchemy/sql/sqltypes.py,sha256=d3xNVCDPV2MaPInKWvIpLDGS8NwGFLP614_dWws3B_U,126808 | ||
| sqlalchemy/sql/traversals.py,sha256=NFgJrVJzInO3HrnG90CklxrDXhFydZohPs2vRJkh3Bo,33589 | ||
| sqlalchemy/sql/type_api.py,sha256=CJAvRix_rRoOsE77sH4BqeGX0lIdtk8dX-StjGx3mUo,83208 | ||
| sqlalchemy/sql/util.py,sha256=qGHQF-tPCj-m1FBerzT7weCanGcXU7dK5m-W7NHio-4,48077 | ||
| sqlalchemy/sql/visitors.py,sha256=71wdVvhhZL4nJvVwFAs6ssaW-qZgNRSmKjpAcOzF_TA,36317 | ||
| sqlalchemy/testing/__init__.py,sha256=VsrEHrORpAF5n7Vfl43YQgABh6EP1xBx_gHxs7pSXeE,3126 | ||
| sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/config.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/engines.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/entities.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/provision.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/schema.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/util.cpython-312.pyc,, | ||
| sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc,, | ||
| sqlalchemy/testing/assertions.py,sha256=gL0rA7CCZJbcVgvWOPV91tTZTRwQc1_Ta0-ykBn83Ew,31439 | ||
| sqlalchemy/testing/assertsql.py,sha256=IgQG7l94WaiRP8nTbilJh1ZHZl125g7GPq-S5kmQZN0,16817 | ||
| sqlalchemy/testing/asyncio.py,sha256=kM8uuOqDBagZF0r9xvGmsiirUVLUQ_KBzjUFU67W-b8,3830 | ||
| sqlalchemy/testing/config.py,sha256=AqyH1qub_gDqX0BvlL-JBQe7N-t2wo8655FtwblUNOY,12090 | ||
| sqlalchemy/testing/engines.py,sha256=HFJceEBD3Q_TTFQMTtIV5wGWO_a7oUgoKtUF_z636SM,13481 | ||
| sqlalchemy/testing/entities.py,sha256=IphFegPKbff3Un47jY6bi7_MQXy6qkx_50jX2tHZJR4,3354 | ||
| sqlalchemy/testing/exclusions.py,sha256=T8B01hmm8WVs-EKcUOQRzabahPqblWJfOidi6bHJ6GA,12460 | ||
| sqlalchemy/testing/fixtures/__init__.py,sha256=dMClrIoxqlYIFpk2ia4RZpkbfxsS_3EBigr9QsPJ66g,1198 | ||
| sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc,, | ||
| sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc,, | ||
| sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc,, | ||
| sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc,, | ||
| sqlalchemy/testing/fixtures/base.py,sha256=9r_J2ksiTzClpUxW0TczICHrWR7Ny8PV8IsBz6TsGFI,12256 | ||
| sqlalchemy/testing/fixtures/mypy.py,sha256=gdxiwNFIzDlNGSOdvM3gbwDceVCC9t8oM5kKbwyhGBk,11973 | ||
| sqlalchemy/testing/fixtures/orm.py,sha256=8EFbnaBbXX_Bf4FcCzBUaAHgyVpsLGBHX16SGLqE3Fg,6095 | ||
| sqlalchemy/testing/fixtures/sql.py,sha256=TE5q2BSOc_Vq1TPaLnj1F9ZA_YiQHlqyvUtGId9bGr0,15774 | ||
| sqlalchemy/testing/pickleable.py,sha256=U9mIqk-zaxq9Xfy7HErP7UrKgTov-A3QFnhZh-NiOjI,2833 | ||
| sqlalchemy/testing/plugin/__init__.py,sha256=79F--BIY_NTBzVRIlJGgAY5LNJJ3cD19XvrAo4X0W9A,247 | ||
| sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc,, | ||
| sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc,, | ||
| sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc,, | ||
| sqlalchemy/testing/plugin/bootstrap.py,sha256=oYScMbEW4pCnWlPEAq1insFruCXFQeEVBwo__i4McpU,1685 | ||
| sqlalchemy/testing/plugin/plugin_base.py,sha256=BgNzWNEmgpK4CwhyblQQKnH-7FDKVi_Uul5vw8fFjBU,21578 | ||
| sqlalchemy/testing/plugin/pytestplugin.py,sha256=6jkQHH2VQMD75k2As9CuWXmEy9jrscoFRhCNg6-PaTw,27656 | ||
| sqlalchemy/testing/profiling.py,sha256=PbuPhRFbauFilUONeY3tV_Y_5lBkD7iCa8VVyH2Sk9Y,10148 | ||
| sqlalchemy/testing/provision.py,sha256=zXsw2D2Xpmw_chmYLsE1GXQqKQ-so3V8xU_joTcKan0,14619 | ||
| sqlalchemy/testing/requirements.py,sha256=N9pSj7z2wVMkBif-DQfPVa_cl9k6p9g_J5FY1OsWtrY,51817 | ||
| sqlalchemy/testing/schema.py,sha256=lr4GkGrGwagaHMuSGzWdzkMaj3HnS7dgfLLWfxt__-U,6513 | ||
| sqlalchemy/testing/suite/__init__.py,sha256=Y5DRNG0Yl1u3ypt9zVF0Z9suPZeuO_UQGLl-wRgvTjU,722 | ||
| sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc,, | ||
| sqlalchemy/testing/suite/test_cte.py,sha256=6zBC3W2OwX1Xs-HedzchcKN2S7EaLNkgkvV_JSZ_Pq0,6451 | ||
| sqlalchemy/testing/suite/test_ddl.py,sha256=1Npkf0C_4UNxphthAGjG078n0vPEgnSIHpDu5MfokxQ,12031 | ||
| sqlalchemy/testing/suite/test_deprecations.py,sha256=BcJxZTcjYqeOAENVElCg3hVvU6fkGEW3KGBMfnW8bng,5337 | ||
| sqlalchemy/testing/suite/test_dialect.py,sha256=EH4ZQWbnGdtjmx5amZtTyhYmrkXJCvW1SQoLahoE7uk,22923 | ||
| sqlalchemy/testing/suite/test_insert.py,sha256=9azifj6-OCD7s8h_tAO1uPw100ibQv8YoKc_VA3hn3c,18824 | ||
| sqlalchemy/testing/suite/test_reflection.py,sha256=tJSbJFg5fw0sSUv3I_FPmhN7rWWeJtq3YyxmylWJUlM,106466 | ||
| sqlalchemy/testing/suite/test_results.py,sha256=NQ23m8FDVd0ub751jN4PswGoAhk5nrqvjHvpYULZXnc,15937 | ||
| sqlalchemy/testing/suite/test_rowcount.py,sha256=3KDTlRgjpQ1OVfp__1cv8Hvq4CsDKzmrhJQ_WIJWoJg,7900 | ||
| sqlalchemy/testing/suite/test_select.py,sha256=FvMFYQW9IJpDWGYZiJk46is6YrtmdSghBdTjZCG8T0Y,58574 | ||
| sqlalchemy/testing/suite/test_sequence.py,sha256=66bCoy4xo99GBSaX6Hxb88foANAykLGRz1YEKbvpfuA,9923 | ||
| sqlalchemy/testing/suite/test_types.py,sha256=rFmTOg6XuMch9L2-XthfLJRCTTwpZbMfrNss2g09gmc,65677 | ||
| sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=c3_eIxLyORuSOhNDP0jWKxPyUf3SwMFpdalxtquwqlM,6141 | ||
| sqlalchemy/testing/suite/test_update_delete.py,sha256=yTiM2unnfOK9rK8ZkqeTTU_MkT-RsKFLmdYliniZfAY,3994 | ||
| sqlalchemy/testing/util.py,sha256=BFiSp3CEX95Dr-vv4l_7ZRu5vjZi9hjjnp-JKNfuS5E,14080 | ||
| sqlalchemy/testing/warnings.py,sha256=fJ-QJUY2zY2PPxZJKv9medW-BKKbCNbA4Ns_V3YwFXM,1546 | ||
| sqlalchemy/types.py,sha256=cQFM-hFRmaf1GErun1qqgEs6QxufvzMuwKqj9tuMPpE,3168 | ||
| sqlalchemy/util/__init__.py,sha256=B3bedg-LSQEscwqgmYYU-VENUX8_zAE3q9vb7tkfJNY,8277 | ||
| sqlalchemy/util/__pycache__/__init__.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/_collections.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/compat.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/queue.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/topological.cpython-312.pyc,, | ||
| sqlalchemy/util/__pycache__/typing.cpython-312.pyc,, | ||
| sqlalchemy/util/_collections.py,sha256=aZoSAVOXnHBoYEsxDOi0O9odg9wqLbGb7PGjaWQKiyY,20078 | ||
| sqlalchemy/util/_concurrency_py3k.py,sha256=zb0Bow2Y_QjTdaACEviBEEaFvqDuVvpJfmwCjaw8xNE,9170 | ||
| sqlalchemy/util/_has_cy.py,sha256=wCQmeSjT3jaH_oxfCEtGk-1g0gbSpt5MCK5UcWdMWqk,1247 | ||
| sqlalchemy/util/_py_collections.py,sha256=U6L5AoyLdgSv7cdqB4xxQbw1rpeJjyOZVXffgxgga8I,16714 | ||
| sqlalchemy/util/compat.py,sha256=R6bpBydldtbr6h7oJePihQxFb7jKiI-YDsK465MSOzk,8714 | ||
| sqlalchemy/util/concurrency.py,sha256=9lT_cMoO1fZNdY8QTUZ22oeSf-L5I-79Ke7chcBNPA0,3304 | ||
| sqlalchemy/util/deprecations.py,sha256=YBwvvYhSB8LhasIZRKvg_-WNoVhPUcaYI1ZrnjDn868,11971 | ||
| sqlalchemy/util/langhelpers.py,sha256=5XpX5X6sqKtZ6B07WmlP2oOCbUn7CptBNVTe4LR7jqA,64957 | ||
| sqlalchemy/util/preloaded.py,sha256=az7NmLJLsqs0mtM9uBkIu10-841RYDq8wOyqJ7xXvqE,5904 | ||
| sqlalchemy/util/queue.py,sha256=CaeSEaYZ57YwtmLdNdOIjT5PK_LCuwMFiO0mpp39ybM,10185 | ||
| sqlalchemy/util/tool_support.py,sha256=9braZyidaiNrZVsWtGmkSmus50-byhuYrlAqvhjcmnA,6135 | ||
| sqlalchemy/util/topological.py,sha256=N3M3Le7KzGHCmqPGg0ZBqixTDGwmFLhOZvBtc4rHL_g,3458 | ||
| sqlalchemy/util/typing.py,sha256=UctfgugSTnFJgZraikXJbB-5RoV7oyccZmbf2NeRfoA,16671 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not commit virtual environment files to version control.
The .venv/ directory contains auto-generated package installation artifacts and must be excluded from the repository. Committing these files:
- Bloats the repository with thousands of unnecessary files
- Creates merge conflicts when developers use different environments
- Breaks portability across platforms and Python versions
Remove these files and add .venv/ to .gitignore.
#!/bin/bash
# Check if .venv is already in .gitignore
if [ -f .gitignore ]; then
echo "=== Checking .gitignore for .venv exclusion ==="
grep -E '^\s*\.?venv' .gitignore || echo ".venv is NOT in .gitignore"
else
echo ".gitignore file does not exist"
fi
# Check how many .venv files are staged
echo ""
echo "=== Counting .venv files in repository ==="
fd . .venv --type f 2>/dev/null | wc -l || echo "Could not count .venv files"🤖 Prompt for AI Agents
In .venv/lib/python3.12/site-packages/SQLAlchemy-2.0.31.dist-info/RECORD lines
1-530: the review flags that the entire .venv directory (including this RECORD
file) must not be committed; remove the committed virtualenv files and ensure
.venv is ignored. Fix by removing the .venv files from the repository
history/staging (e.g. git rm -r --cached .venv or remove and restore from a
clean branch), add a rule for .venv to .gitignore (ensure pattern matches your
venv name), and commit the .gitignore change and the removal commit so .venv is
no longer tracked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.gitignore (1)
1-9: Enhance.gitignorewith additional Python project patterns.The
.gitignorecovers basic virtual environment and cache patterns, but is missing several common Python project artifacts. Consider adding patterns for:
- Additional bytecode formats:
*.pyo,*.pyd- Distribution/build artifacts:
build/,dist/,*.egg-info/,.eggs/- Testing:
.pytest_cache/,.coverage,htmlcov/,.tox/- Python metadata:
.Python- IDE/editor configs:
.vscode/,.idea/,*.swp,*.swo,*~- OS files:
.DS_StoreConsider applying this enhanced
.gitignore:# Virtual environments .venv/ venv/ ENV/ env/ # Python __pycache__/ *.pyc +*.pyo +*.pyd +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Testing +.pytest_cache/ +.coverage +htmlcov/ +.tox/ + +# IDE +.vscode/ +.idea/ +*.iml +*.swp +*.swo +*~ + +# OS +.DS_Store
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.gitignore(1 hunks).venv/bin/python(0 hunks).venv/bin/python3(0 hunks).venv/bin/python3.12(0 hunks)
💤 Files with no reviewable changes (3)
- .venv/bin/python3.12
- .venv/bin/python
- .venv/bin/python3
🔇 Additional comments (1)
.gitignore (1)
1-9: Discrepancy: PR objectives mentiontime_tracker.pybut only.gitignoreis provided.The PR objectives describe adding a new
time_tracker.pyfile withstart_timer()andfinish_timer()functions underapp/core/. However, only.gitignoreis included in the provided files for review. Please confirm whethertime_tracker.pyshould also be included in this review.
Changes requested:
Create
time_tracker.pyinapp/core/. Add functionsstart_timer(report_id)andfinish_timer(report_id)that record start and end timestamps using database storage or Redis. Compute total time taken for each report.Please review.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.