Instructions to use FerrellSyntheticIntelligence/fsi-anomaly with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use FerrellSyntheticIntelligence/fsi-anomaly with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: llama cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: llama cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: ./llama-cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf FerrellSyntheticIntelligence/fsi-anomaly # Run inference directly in the terminal: ./build/bin/llama-cli -hf FerrellSyntheticIntelligence/fsi-anomaly
Use Docker
docker model run hf.co/FerrellSyntheticIntelligence/fsi-anomaly
- LM Studio
- Jan
- Ollama
How to use FerrellSyntheticIntelligence/fsi-anomaly with Ollama:
ollama run hf.co/FerrellSyntheticIntelligence/fsi-anomaly
- Unsloth Desktop
- Docker Model Runner
How to use FerrellSyntheticIntelligence/fsi-anomaly with Docker Model Runner:
docker model run hf.co/FerrellSyntheticIntelligence/fsi-anomaly
- Lemonade
How to use FerrellSyntheticIntelligence/fsi-anomaly with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull FerrellSyntheticIntelligence/fsi-anomaly
Run and chat with the model
lemonade run user.fsi-anomaly-{{QUANT_TAG}}List all available models
lemonade list
- Atomic Chat
remove venv/cache junk from failed first upload
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .pytest_cache/.gitignore +0 -2
- .pytest_cache/CACHEDIR.TAG +0 -4
- .pytest_cache/README.md +0 -8
- .pytest_cache/v/cache/lastfailed +0 -1
- .pytest_cache/v/cache/nodeids +0 -71
- .venv/bin/Activate.ps1 +0 -247
- .venv/bin/activate +0 -70
- .venv/bin/activate.csh +0 -27
- .venv/bin/activate.fish +0 -69
- .venv/bin/debugpy +0 -6
- .venv/bin/debugpy-adapter +0 -6
- .venv/bin/f2py +0 -6
- .venv/bin/gguf-convert-endian +0 -6
- .venv/bin/gguf-dump +0 -6
- .venv/bin/gguf-editor-gui +0 -6
- .venv/bin/gguf-new-metadata +0 -6
- .venv/bin/gguf-set-metadata +0 -6
- .venv/bin/hf +0 -6
- .venv/bin/httpx +0 -6
- .venv/bin/huggingface-cli +0 -6
- .venv/bin/idna +0 -6
- .venv/bin/isympy +0 -6
- .venv/bin/markdown-it +0 -6
- .venv/bin/normalizer +0 -6
- .venv/bin/numpy-config +0 -6
- .venv/bin/pip +0 -8
- .venv/bin/pip3 +0 -8
- .venv/bin/pip3.12 +0 -8
- .venv/bin/py-spy +0 -3
- .venv/bin/py.test +0 -6
- .venv/bin/pygmentize +0 -6
- .venv/bin/pytest +0 -6
- .venv/bin/python +0 -3
- .venv/bin/python3 +0 -3
- .venv/bin/python3.12 +0 -3
- .venv/bin/tiny-agents +0 -6
- .venv/bin/torchfrtrace +0 -6
- .venv/bin/torchrun +0 -6
- .venv/bin/tqdm +0 -6
- .venv/bin/transformers +0 -6
- .venv/bin/typer +0 -6
- .venv/lib/python3.12/site-packages/_distutils_hack/__init__.py +0 -239
- .venv/lib/python3.12/site-packages/_distutils_hack/override.py +0 -1
- .venv/lib/python3.12/site-packages/_pytest/__init__.py +0 -13
- .venv/lib/python3.12/site-packages/_pytest/_argcomplete.py +0 -117
- .venv/lib/python3.12/site-packages/_pytest/_code/__init__.py +0 -26
- .venv/lib/python3.12/site-packages/_pytest/_code/code.py +0 -1632
- .venv/lib/python3.12/site-packages/_pytest/_code/source.py +0 -228
- .venv/lib/python3.12/site-packages/_pytest/_io/__init__.py +0 -10
- .venv/lib/python3.12/site-packages/_pytest/_io/pprint.py +0 -673
.pytest_cache/.gitignore
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
# Created by pytest automatically.
|
| 2 |
-
*
|
|
|
|
|
|
|
|
|
.pytest_cache/CACHEDIR.TAG
DELETED
|
@@ -1,4 +0,0 @@
|
|
| 1 |
-
Signature: 8a477f597d28d172789f06886806bc55
|
| 2 |
-
# This file is a cache directory tag created by pytest.
|
| 3 |
-
# For information about cache directory tags, see:
|
| 4 |
-
# https://bford.info/cachedir/spec.html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.pytest_cache/README.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
# pytest cache directory #
|
| 2 |
-
|
| 3 |
-
This directory contains data from the pytest's cache plugin,
|
| 4 |
-
which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
|
| 5 |
-
|
| 6 |
-
**Do not** commit this to version control.
|
| 7 |
-
|
| 8 |
-
See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.pytest_cache/v/cache/lastfailed
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{}
|
|
|
|
|
|
.pytest_cache/v/cache/nodeids
DELETED
|
@@ -1,71 +0,0 @@
|
|
| 1 |
-
[
|
| 2 |
-
"tests/test_decision.py::test_accuracy_vs_coverage_monotone",
|
| 3 |
-
"tests/test_decision.py::test_bucket_abstention_curve",
|
| 4 |
-
"tests/test_decision.py::test_bucket_for",
|
| 5 |
-
"tests/test_decision.py::test_conflict_attenuated",
|
| 6 |
-
"tests/test_decision.py::test_majority_outweighs_minority",
|
| 7 |
-
"tests/test_decision.py::test_unanimous_high_vote",
|
| 8 |
-
"tests/test_decision.py::test_unanimous_low_abstains",
|
| 9 |
-
"tests/test_decision.py::test_unknown_bucket_abstains_above_zero_threshold",
|
| 10 |
-
"tests/test_decision.py::test_weighted_tally",
|
| 11 |
-
"tests/test_dpo_lfm2.py::test_apo_term_rewards_absolute_gap",
|
| 12 |
-
"tests/test_dpo_lfm2.py::test_margin_increases_loss_for_close_pairs",
|
| 13 |
-
"tests/test_dpo_lfm2.py::test_plain_dpo_special_case",
|
| 14 |
-
"tests/test_dpo_lr_schedule.py::test_constant_schedule_keeps_lr",
|
| 15 |
-
"tests/test_dpo_lr_schedule.py::test_cosine_warmup_then_decay",
|
| 16 |
-
"tests/test_dpo_lr_schedule.py::test_warmup_frac_scales",
|
| 17 |
-
"tests/test_eval_summary.py::test_scored_ids_whole_file",
|
| 18 |
-
"tests/test_eval_summary.py::test_summarize_dedupes_resume_sections",
|
| 19 |
-
"tests/test_eval_summary.py::test_summarize_exact",
|
| 20 |
-
"tests/test_guardrails.py::test_clean_research_input_passes",
|
| 21 |
-
"tests/test_guardrails.py::test_instruction_override_flagged",
|
| 22 |
-
"tests/test_guardrails.py::test_offtopic_flagged",
|
| 23 |
-
"tests/test_guardrails.py::test_output_abstain_mismatch_flagged",
|
| 24 |
-
"tests/test_guardrails.py::test_output_clean_passes",
|
| 25 |
-
"tests/test_guardrails.py::test_output_valid_missing_confidence_flagged",
|
| 26 |
-
"tests/test_guardrails.py::test_pii_redacted",
|
| 27 |
-
"tests/test_guardrails.py::test_roleplay_extraction_flagged",
|
| 28 |
-
"tests/test_helix_memory.py::test_helix_forget_and_stats",
|
| 29 |
-
"tests/test_helix_memory.py::test_helix_recall_bridges_cases_and_keeps_receipts",
|
| 30 |
-
"tests/test_journalism.py::test_casefile_roundtrip",
|
| 31 |
-
"tests/test_journalism.py::test_editorial_review_clean",
|
| 32 |
-
"tests/test_journalism.py::test_editorial_review_flags",
|
| 33 |
-
"tests/test_journalism.py::test_entitygraph_edges_and_centrality",
|
| 34 |
-
"tests/test_journalism.py::test_framing_omissions",
|
| 35 |
-
"tests/test_journalism.py::test_framing_passive_loaded_hedges",
|
| 36 |
-
"tests/test_journalism.py::test_patterns_shared_rungs_and_themes",
|
| 37 |
-
"tests/test_journalism.py::test_provenance_chain_and_single_source",
|
| 38 |
-
"tests/test_journalism.py::test_provenance_credibility_tiers",
|
| 39 |
-
"tests/test_journalism.py::test_source_policy_rejects_untraceable_or_duplicate_leads",
|
| 40 |
-
"tests/test_journalism.py::test_source_policy_requires_independent_traceable_corroboration",
|
| 41 |
-
"tests/test_journalism.py::test_suite_report_end_to_end",
|
| 42 |
-
"tests/test_journalism.py::test_suite_report_fails_closed_without_source_policy_metadata",
|
| 43 |
-
"tests/test_journalism.py::test_timeline_anachronism",
|
| 44 |
-
"tests/test_journalism.py::test_timeline_gaps_and_cliffs",
|
| 45 |
-
"tests/test_lora_fold.py::test_fold_preserves_bias",
|
| 46 |
-
"tests/test_merges.py::test_soup_taskarith_intersect_keys",
|
| 47 |
-
"tests/test_merges.py::test_ties_merge_ignores_missing_task_keys",
|
| 48 |
-
"tests/test_merges.py::test_trim_delta_preserves_top_fraction_shape",
|
| 49 |
-
"tests/test_mtp.py::test_forward_mtp_shapes",
|
| 50 |
-
"tests/test_mtp.py::test_mtp_checkpoint_roundtrip",
|
| 51 |
-
"tests/test_mtp.py::test_mtp_loss_backward",
|
| 52 |
-
"tests/test_mtp.py::test_train_lm_mtp_smoke",
|
| 53 |
-
"tests/test_posttrain.py::test_rlvr_card_trace",
|
| 54 |
-
"tests/test_posttrain.py::test_rlvr_reward_abstain_is_zero",
|
| 55 |
-
"tests/test_posttrain.py::test_rlvr_reward_correct_with_citation",
|
| 56 |
-
"tests/test_posttrain.py::test_rlvr_reward_false_citation_penalty",
|
| 57 |
-
"tests/test_posttrain.py::test_rlvr_reward_wrong_verdict",
|
| 58 |
-
"tests/test_posttrain.py::test_ties_sign_consensus",
|
| 59 |
-
"tests/test_posttrain.py::test_trim_keeps_topk",
|
| 60 |
-
"tests/test_verify_loop.py::test_plan_checks_extracts_values",
|
| 61 |
-
"tests/test_verify_loop.py::test_run_checks_no_evidence",
|
| 62 |
-
"tests/test_verify_loop.py::test_run_checks_refutes",
|
| 63 |
-
"tests/test_verify_loop.py::test_run_checks_supports",
|
| 64 |
-
"tests/test_verify_loop.py::test_strict_policy_fails_closed_on_a_single_untraceable_lead",
|
| 65 |
-
"tests/test_verify_loop.py::test_strict_policy_overrides_an_incorrect_model_draft",
|
| 66 |
-
"tests/test_verify_loop.py::test_verify_case_defaults_to_fail_closed_source_policy",
|
| 67 |
-
"tests/test_verify_loop.py::test_verify_case_rule_refuted_wins",
|
| 68 |
-
"tests/test_verify_loop.py::test_verify_case_rule_verified",
|
| 69 |
-
"tests/test_verify_loop.py::test_verify_case_unresolved_downgrades_high",
|
| 70 |
-
"tests/test_verify_loop.py::test_verify_case_unresolved_keeps_low"
|
| 71 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/Activate.ps1
DELETED
|
@@ -1,247 +0,0 @@
|
|
| 1 |
-
<#
|
| 2 |
-
.Synopsis
|
| 3 |
-
Activate a Python virtual environment for the current PowerShell session.
|
| 4 |
-
|
| 5 |
-
.Description
|
| 6 |
-
Pushes the python executable for a virtual environment to the front of the
|
| 7 |
-
$Env:PATH environment variable and sets the prompt to signify that you are
|
| 8 |
-
in a Python virtual environment. Makes use of the command line switches as
|
| 9 |
-
well as the `pyvenv.cfg` file values present in the virtual environment.
|
| 10 |
-
|
| 11 |
-
.Parameter VenvDir
|
| 12 |
-
Path to the directory that contains the virtual environment to activate. The
|
| 13 |
-
default value for this is the parent of the directory that the Activate.ps1
|
| 14 |
-
script is located within.
|
| 15 |
-
|
| 16 |
-
.Parameter Prompt
|
| 17 |
-
The prompt prefix to display when this virtual environment is activated. By
|
| 18 |
-
default, this prompt is the name of the virtual environment folder (VenvDir)
|
| 19 |
-
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
|
| 20 |
-
|
| 21 |
-
.Example
|
| 22 |
-
Activate.ps1
|
| 23 |
-
Activates the Python virtual environment that contains the Activate.ps1 script.
|
| 24 |
-
|
| 25 |
-
.Example
|
| 26 |
-
Activate.ps1 -Verbose
|
| 27 |
-
Activates the Python virtual environment that contains the Activate.ps1 script,
|
| 28 |
-
and shows extra information about the activation as it executes.
|
| 29 |
-
|
| 30 |
-
.Example
|
| 31 |
-
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
|
| 32 |
-
Activates the Python virtual environment located in the specified location.
|
| 33 |
-
|
| 34 |
-
.Example
|
| 35 |
-
Activate.ps1 -Prompt "MyPython"
|
| 36 |
-
Activates the Python virtual environment that contains the Activate.ps1 script,
|
| 37 |
-
and prefixes the current prompt with the specified string (surrounded in
|
| 38 |
-
parentheses) while the virtual environment is active.
|
| 39 |
-
|
| 40 |
-
.Notes
|
| 41 |
-
On Windows, it may be required to enable this Activate.ps1 script by setting the
|
| 42 |
-
execution policy for the user. You can do this by issuing the following PowerShell
|
| 43 |
-
command:
|
| 44 |
-
|
| 45 |
-
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
| 46 |
-
|
| 47 |
-
For more information on Execution Policies:
|
| 48 |
-
https://go.microsoft.com/fwlink/?LinkID=135170
|
| 49 |
-
|
| 50 |
-
#>
|
| 51 |
-
Param(
|
| 52 |
-
[Parameter(Mandatory = $false)]
|
| 53 |
-
[String]
|
| 54 |
-
$VenvDir,
|
| 55 |
-
[Parameter(Mandatory = $false)]
|
| 56 |
-
[String]
|
| 57 |
-
$Prompt
|
| 58 |
-
)
|
| 59 |
-
|
| 60 |
-
<# Function declarations --------------------------------------------------- #>
|
| 61 |
-
|
| 62 |
-
<#
|
| 63 |
-
.Synopsis
|
| 64 |
-
Remove all shell session elements added by the Activate script, including the
|
| 65 |
-
addition of the virtual environment's Python executable from the beginning of
|
| 66 |
-
the PATH variable.
|
| 67 |
-
|
| 68 |
-
.Parameter NonDestructive
|
| 69 |
-
If present, do not remove this function from the global namespace for the
|
| 70 |
-
session.
|
| 71 |
-
|
| 72 |
-
#>
|
| 73 |
-
function global:deactivate ([switch]$NonDestructive) {
|
| 74 |
-
# Revert to original values
|
| 75 |
-
|
| 76 |
-
# The prior prompt:
|
| 77 |
-
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
|
| 78 |
-
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
|
| 79 |
-
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
# The prior PYTHONHOME:
|
| 83 |
-
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
|
| 84 |
-
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
|
| 85 |
-
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
|
| 86 |
-
}
|
| 87 |
-
|
| 88 |
-
# The prior PATH:
|
| 89 |
-
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
|
| 90 |
-
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
|
| 91 |
-
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
|
| 92 |
-
}
|
| 93 |
-
|
| 94 |
-
# Just remove the VIRTUAL_ENV altogether:
|
| 95 |
-
if (Test-Path -Path Env:VIRTUAL_ENV) {
|
| 96 |
-
Remove-Item -Path env:VIRTUAL_ENV
|
| 97 |
-
}
|
| 98 |
-
|
| 99 |
-
# Just remove VIRTUAL_ENV_PROMPT altogether.
|
| 100 |
-
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
|
| 101 |
-
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
|
| 102 |
-
}
|
| 103 |
-
|
| 104 |
-
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
|
| 105 |
-
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
|
| 106 |
-
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
|
| 107 |
-
}
|
| 108 |
-
|
| 109 |
-
# Leave deactivate function in the global namespace if requested:
|
| 110 |
-
if (-not $NonDestructive) {
|
| 111 |
-
Remove-Item -Path function:deactivate
|
| 112 |
-
}
|
| 113 |
-
}
|
| 114 |
-
|
| 115 |
-
<#
|
| 116 |
-
.Description
|
| 117 |
-
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
|
| 118 |
-
given folder, and returns them in a map.
|
| 119 |
-
|
| 120 |
-
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
|
| 121 |
-
two strings separated by `=` (with any amount of whitespace surrounding the =)
|
| 122 |
-
then it is considered a `key = value` line. The left hand string is the key,
|
| 123 |
-
the right hand is the value.
|
| 124 |
-
|
| 125 |
-
If the value starts with a `'` or a `"` then the first and last character is
|
| 126 |
-
stripped from the value before being captured.
|
| 127 |
-
|
| 128 |
-
.Parameter ConfigDir
|
| 129 |
-
Path to the directory that contains the `pyvenv.cfg` file.
|
| 130 |
-
#>
|
| 131 |
-
function Get-PyVenvConfig(
|
| 132 |
-
[String]
|
| 133 |
-
$ConfigDir
|
| 134 |
-
) {
|
| 135 |
-
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
|
| 136 |
-
|
| 137 |
-
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
|
| 138 |
-
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
|
| 139 |
-
|
| 140 |
-
# An empty map will be returned if no config file is found.
|
| 141 |
-
$pyvenvConfig = @{ }
|
| 142 |
-
|
| 143 |
-
if ($pyvenvConfigPath) {
|
| 144 |
-
|
| 145 |
-
Write-Verbose "File exists, parse `key = value` lines"
|
| 146 |
-
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
|
| 147 |
-
|
| 148 |
-
$pyvenvConfigContent | ForEach-Object {
|
| 149 |
-
$keyval = $PSItem -split "\s*=\s*", 2
|
| 150 |
-
if ($keyval[0] -and $keyval[1]) {
|
| 151 |
-
$val = $keyval[1]
|
| 152 |
-
|
| 153 |
-
# Remove extraneous quotations around a string value.
|
| 154 |
-
if ("'""".Contains($val.Substring(0, 1))) {
|
| 155 |
-
$val = $val.Substring(1, $val.Length - 2)
|
| 156 |
-
}
|
| 157 |
-
|
| 158 |
-
$pyvenvConfig[$keyval[0]] = $val
|
| 159 |
-
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
|
| 160 |
-
}
|
| 161 |
-
}
|
| 162 |
-
}
|
| 163 |
-
return $pyvenvConfig
|
| 164 |
-
}
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
<# Begin Activate script --------------------------------------------------- #>
|
| 168 |
-
|
| 169 |
-
# Determine the containing directory of this script
|
| 170 |
-
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
| 171 |
-
$VenvExecDir = Get-Item -Path $VenvExecPath
|
| 172 |
-
|
| 173 |
-
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
|
| 174 |
-
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
|
| 175 |
-
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
|
| 176 |
-
|
| 177 |
-
# Set values required in priority: CmdLine, ConfigFile, Default
|
| 178 |
-
# First, get the location of the virtual environment, it might not be
|
| 179 |
-
# VenvExecDir if specified on the command line.
|
| 180 |
-
if ($VenvDir) {
|
| 181 |
-
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
|
| 182 |
-
}
|
| 183 |
-
else {
|
| 184 |
-
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
|
| 185 |
-
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
|
| 186 |
-
Write-Verbose "VenvDir=$VenvDir"
|
| 187 |
-
}
|
| 188 |
-
|
| 189 |
-
# Next, read the `pyvenv.cfg` file to determine any required value such
|
| 190 |
-
# as `prompt`.
|
| 191 |
-
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
|
| 192 |
-
|
| 193 |
-
# Next, set the prompt from the command line, or the config file, or
|
| 194 |
-
# just use the name of the virtual environment folder.
|
| 195 |
-
if ($Prompt) {
|
| 196 |
-
Write-Verbose "Prompt specified as argument, using '$Prompt'"
|
| 197 |
-
}
|
| 198 |
-
else {
|
| 199 |
-
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
|
| 200 |
-
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
|
| 201 |
-
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
|
| 202 |
-
$Prompt = $pyvenvCfg['prompt'];
|
| 203 |
-
}
|
| 204 |
-
else {
|
| 205 |
-
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
|
| 206 |
-
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
|
| 207 |
-
$Prompt = Split-Path -Path $venvDir -Leaf
|
| 208 |
-
}
|
| 209 |
-
}
|
| 210 |
-
|
| 211 |
-
Write-Verbose "Prompt = '$Prompt'"
|
| 212 |
-
Write-Verbose "VenvDir='$VenvDir'"
|
| 213 |
-
|
| 214 |
-
# Deactivate any currently active virtual environment, but leave the
|
| 215 |
-
# deactivate function in place.
|
| 216 |
-
deactivate -nondestructive
|
| 217 |
-
|
| 218 |
-
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
|
| 219 |
-
# that there is an activated venv.
|
| 220 |
-
$env:VIRTUAL_ENV = $VenvDir
|
| 221 |
-
|
| 222 |
-
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
|
| 223 |
-
|
| 224 |
-
Write-Verbose "Setting prompt to '$Prompt'"
|
| 225 |
-
|
| 226 |
-
# Set the prompt to include the env name
|
| 227 |
-
# Make sure _OLD_VIRTUAL_PROMPT is global
|
| 228 |
-
function global:_OLD_VIRTUAL_PROMPT { "" }
|
| 229 |
-
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
|
| 230 |
-
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
|
| 231 |
-
|
| 232 |
-
function global:prompt {
|
| 233 |
-
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
|
| 234 |
-
_OLD_VIRTUAL_PROMPT
|
| 235 |
-
}
|
| 236 |
-
$env:VIRTUAL_ENV_PROMPT = $Prompt
|
| 237 |
-
}
|
| 238 |
-
|
| 239 |
-
# Clear PYTHONHOME
|
| 240 |
-
if (Test-Path -Path Env:PYTHONHOME) {
|
| 241 |
-
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
|
| 242 |
-
Remove-Item -Path Env:PYTHONHOME
|
| 243 |
-
}
|
| 244 |
-
|
| 245 |
-
# Add the venv to the PATH
|
| 246 |
-
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
|
| 247 |
-
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/activate
DELETED
|
@@ -1,70 +0,0 @@
|
|
| 1 |
-
# This file must be used with "source bin/activate" *from bash*
|
| 2 |
-
# You cannot run it directly
|
| 3 |
-
|
| 4 |
-
deactivate () {
|
| 5 |
-
# reset old environment variables
|
| 6 |
-
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
|
| 7 |
-
PATH="${_OLD_VIRTUAL_PATH:-}"
|
| 8 |
-
export PATH
|
| 9 |
-
unset _OLD_VIRTUAL_PATH
|
| 10 |
-
fi
|
| 11 |
-
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
|
| 12 |
-
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
|
| 13 |
-
export PYTHONHOME
|
| 14 |
-
unset _OLD_VIRTUAL_PYTHONHOME
|
| 15 |
-
fi
|
| 16 |
-
|
| 17 |
-
# Call hash to forget past commands. Without forgetting
|
| 18 |
-
# past commands the $PATH changes we made may not be respected
|
| 19 |
-
hash -r 2> /dev/null
|
| 20 |
-
|
| 21 |
-
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
|
| 22 |
-
PS1="${_OLD_VIRTUAL_PS1:-}"
|
| 23 |
-
export PS1
|
| 24 |
-
unset _OLD_VIRTUAL_PS1
|
| 25 |
-
fi
|
| 26 |
-
|
| 27 |
-
unset VIRTUAL_ENV
|
| 28 |
-
unset VIRTUAL_ENV_PROMPT
|
| 29 |
-
if [ ! "${1:-}" = "nondestructive" ] ; then
|
| 30 |
-
# Self destruct!
|
| 31 |
-
unset -f deactivate
|
| 32 |
-
fi
|
| 33 |
-
}
|
| 34 |
-
|
| 35 |
-
# unset irrelevant variables
|
| 36 |
-
deactivate nondestructive
|
| 37 |
-
|
| 38 |
-
# on Windows, a path can contain colons and backslashes and has to be converted:
|
| 39 |
-
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
|
| 40 |
-
# transform D:\path\to\venv to /d/path/to/venv on MSYS
|
| 41 |
-
# and to /cygdrive/d/path/to/venv on Cygwin
|
| 42 |
-
export VIRTUAL_ENV=$(cygpath /root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv)
|
| 43 |
-
else
|
| 44 |
-
# use the path as-is
|
| 45 |
-
export VIRTUAL_ENV=/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv
|
| 46 |
-
fi
|
| 47 |
-
|
| 48 |
-
_OLD_VIRTUAL_PATH="$PATH"
|
| 49 |
-
PATH="$VIRTUAL_ENV/"bin":$PATH"
|
| 50 |
-
export PATH
|
| 51 |
-
|
| 52 |
-
# unset PYTHONHOME if set
|
| 53 |
-
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
|
| 54 |
-
# could use `if (set -u; : $PYTHONHOME) ;` in bash
|
| 55 |
-
if [ -n "${PYTHONHOME:-}" ] ; then
|
| 56 |
-
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
|
| 57 |
-
unset PYTHONHOME
|
| 58 |
-
fi
|
| 59 |
-
|
| 60 |
-
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
|
| 61 |
-
_OLD_VIRTUAL_PS1="${PS1:-}"
|
| 62 |
-
PS1='(.venv) '"${PS1:-}"
|
| 63 |
-
export PS1
|
| 64 |
-
VIRTUAL_ENV_PROMPT='(.venv) '
|
| 65 |
-
export VIRTUAL_ENV_PROMPT
|
| 66 |
-
fi
|
| 67 |
-
|
| 68 |
-
# Call hash to forget past commands. Without forgetting
|
| 69 |
-
# past commands the $PATH changes we made may not be respected
|
| 70 |
-
hash -r 2> /dev/null
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/activate.csh
DELETED
|
@@ -1,27 +0,0 @@
|
|
| 1 |
-
# This file must be used with "source bin/activate.csh" *from csh*.
|
| 2 |
-
# You cannot run it directly.
|
| 3 |
-
|
| 4 |
-
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
| 5 |
-
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
|
| 6 |
-
|
| 7 |
-
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
|
| 8 |
-
|
| 9 |
-
# Unset irrelevant variables.
|
| 10 |
-
deactivate nondestructive
|
| 11 |
-
|
| 12 |
-
setenv VIRTUAL_ENV /root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv
|
| 13 |
-
|
| 14 |
-
set _OLD_VIRTUAL_PATH="$PATH"
|
| 15 |
-
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
set _OLD_VIRTUAL_PROMPT="$prompt"
|
| 19 |
-
|
| 20 |
-
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
|
| 21 |
-
set prompt = '(.venv) '"$prompt"
|
| 22 |
-
setenv VIRTUAL_ENV_PROMPT '(.venv) '
|
| 23 |
-
endif
|
| 24 |
-
|
| 25 |
-
alias pydoc python -m pydoc
|
| 26 |
-
|
| 27 |
-
rehash
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/activate.fish
DELETED
|
@@ -1,69 +0,0 @@
|
|
| 1 |
-
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
|
| 2 |
-
# (https://fishshell.com/). You cannot run it directly.
|
| 3 |
-
|
| 4 |
-
function deactivate -d "Exit virtual environment and return to normal shell environment"
|
| 5 |
-
# reset old environment variables
|
| 6 |
-
if test -n "$_OLD_VIRTUAL_PATH"
|
| 7 |
-
set -gx PATH $_OLD_VIRTUAL_PATH
|
| 8 |
-
set -e _OLD_VIRTUAL_PATH
|
| 9 |
-
end
|
| 10 |
-
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
|
| 11 |
-
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
|
| 12 |
-
set -e _OLD_VIRTUAL_PYTHONHOME
|
| 13 |
-
end
|
| 14 |
-
|
| 15 |
-
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
|
| 16 |
-
set -e _OLD_FISH_PROMPT_OVERRIDE
|
| 17 |
-
# prevents error when using nested fish instances (Issue #93858)
|
| 18 |
-
if functions -q _old_fish_prompt
|
| 19 |
-
functions -e fish_prompt
|
| 20 |
-
functions -c _old_fish_prompt fish_prompt
|
| 21 |
-
functions -e _old_fish_prompt
|
| 22 |
-
end
|
| 23 |
-
end
|
| 24 |
-
|
| 25 |
-
set -e VIRTUAL_ENV
|
| 26 |
-
set -e VIRTUAL_ENV_PROMPT
|
| 27 |
-
if test "$argv[1]" != "nondestructive"
|
| 28 |
-
# Self-destruct!
|
| 29 |
-
functions -e deactivate
|
| 30 |
-
end
|
| 31 |
-
end
|
| 32 |
-
|
| 33 |
-
# Unset irrelevant variables.
|
| 34 |
-
deactivate nondestructive
|
| 35 |
-
|
| 36 |
-
set -gx VIRTUAL_ENV /root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv
|
| 37 |
-
|
| 38 |
-
set -gx _OLD_VIRTUAL_PATH $PATH
|
| 39 |
-
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
|
| 40 |
-
|
| 41 |
-
# Unset PYTHONHOME if set.
|
| 42 |
-
if set -q PYTHONHOME
|
| 43 |
-
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
|
| 44 |
-
set -e PYTHONHOME
|
| 45 |
-
end
|
| 46 |
-
|
| 47 |
-
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
|
| 48 |
-
# fish uses a function instead of an env var to generate the prompt.
|
| 49 |
-
|
| 50 |
-
# Save the current fish_prompt function as the function _old_fish_prompt.
|
| 51 |
-
functions -c fish_prompt _old_fish_prompt
|
| 52 |
-
|
| 53 |
-
# With the original prompt function renamed, we can override with our own.
|
| 54 |
-
function fish_prompt
|
| 55 |
-
# Save the return status of the last command.
|
| 56 |
-
set -l old_status $status
|
| 57 |
-
|
| 58 |
-
# Output the venv prompt; color taken from the blue of the Python logo.
|
| 59 |
-
printf "%s%s%s" (set_color 4B8BBE) '(.venv) ' (set_color normal)
|
| 60 |
-
|
| 61 |
-
# Restore the return status of the previous command.
|
| 62 |
-
echo "exit $old_status" | .
|
| 63 |
-
# Output the original/"old" prompt.
|
| 64 |
-
_old_fish_prompt
|
| 65 |
-
end
|
| 66 |
-
|
| 67 |
-
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
|
| 68 |
-
set -gx VIRTUAL_ENV_PROMPT '(.venv) '
|
| 69 |
-
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/debugpy
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from debugpy.server.cli import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/debugpy-adapter
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from debugpy.adapter.__main__ import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/f2py
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from numpy.f2py.f2py2e import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/gguf-convert-endian
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from gguf.scripts.gguf_convert_endian import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/gguf-dump
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from gguf.scripts.gguf_dump import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/gguf-editor-gui
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from gguf.scripts.gguf_editor_gui import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/gguf-new-metadata
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from gguf.scripts.gguf_new_metadata import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/gguf-set-metadata
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from gguf.scripts.gguf_set_metadata import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/hf
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from huggingface_hub.cli.hf import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/httpx
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from httpx import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/huggingface-cli
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from huggingface_hub.cli.deprecated_cli import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/idna
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from idna.cli import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/isympy
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from isympy import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/markdown-it
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from markdown_it.cli.parse import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/normalizer
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from charset_normalizer.cli import cli_detect
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(cli_detect())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/numpy-config
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from numpy._configtool import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/pip
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
# -*- coding: utf-8 -*-
|
| 3 |
-
import re
|
| 4 |
-
import sys
|
| 5 |
-
from pip._internal.cli.main import main
|
| 6 |
-
if __name__ == '__main__':
|
| 7 |
-
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
| 8 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/pip3
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
# -*- coding: utf-8 -*-
|
| 3 |
-
import re
|
| 4 |
-
import sys
|
| 5 |
-
from pip._internal.cli.main import main
|
| 6 |
-
if __name__ == '__main__':
|
| 7 |
-
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
| 8 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/pip3.12
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
# -*- coding: utf-8 -*-
|
| 3 |
-
import re
|
| 4 |
-
import sys
|
| 5 |
-
from pip._internal.cli.main import main
|
| 6 |
-
if __name__ == '__main__':
|
| 7 |
-
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
| 8 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/py-spy
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:d33e743ff7962b4aeefaa34ee87ae1b35e047967f983d660c5335602cb44fba5
|
| 3 |
-
size 7537232
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/py.test
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from _pytest.config import _console_main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(_console_main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/pygmentize
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from pygments.cmdline import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/pytest
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from _pytest.config import _console_main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(_console_main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/python
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:6242e0e8650d7dbdebbc25e08bf4c9359ddaf65f54fcae0e57fa99395fa5357a
|
| 3 |
-
size 7845032
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/python3
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:6242e0e8650d7dbdebbc25e08bf4c9359ddaf65f54fcae0e57fa99395fa5357a
|
| 3 |
-
size 7845032
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/python3.12
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:6242e0e8650d7dbdebbc25e08bf4c9359ddaf65f54fcae0e57fa99395fa5357a
|
| 3 |
-
size 7845032
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/tiny-agents
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from huggingface_hub.inference._mcp.cli import app
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(app())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/torchfrtrace
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from torch.distributed.flight_recorder.fr_trace import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/torchrun
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from torch.distributed.run import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/tqdm
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from tqdm.cli import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/transformers
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from transformers.cli.transformers import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/bin/typer
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
#!/root/Documents/Codex/2026-07-31/so-i-ve-got-a-task/.venv/bin/python3
|
| 2 |
-
import sys
|
| 3 |
-
from typer.cli import main
|
| 4 |
-
if __name__ == '__main__':
|
| 5 |
-
sys.argv[0] = sys.argv[0].removesuffix('.exe')
|
| 6 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_distutils_hack/__init__.py
DELETED
|
@@ -1,239 +0,0 @@
|
|
| 1 |
-
# don't import any costly modules
|
| 2 |
-
import os
|
| 3 |
-
import sys
|
| 4 |
-
|
| 5 |
-
report_url = (
|
| 6 |
-
"https://github.com/pypa/setuptools/issues/new?template=distutils-deprecation.yml"
|
| 7 |
-
)
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
def warn_distutils_present():
|
| 11 |
-
if 'distutils' not in sys.modules:
|
| 12 |
-
return
|
| 13 |
-
import warnings
|
| 14 |
-
|
| 15 |
-
warnings.warn(
|
| 16 |
-
"Distutils was imported before Setuptools, but importing Setuptools "
|
| 17 |
-
"also replaces the `distutils` module in `sys.modules`. This may lead "
|
| 18 |
-
"to undesirable behaviors or errors. To avoid these issues, avoid "
|
| 19 |
-
"using distutils directly, ensure that setuptools is installed in the "
|
| 20 |
-
"traditional way (e.g. not an editable install), and/or make sure "
|
| 21 |
-
"that setuptools is always imported before distutils."
|
| 22 |
-
)
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
def clear_distutils():
|
| 26 |
-
if 'distutils' not in sys.modules:
|
| 27 |
-
return
|
| 28 |
-
import warnings
|
| 29 |
-
|
| 30 |
-
warnings.warn(
|
| 31 |
-
"Setuptools is replacing distutils. Support for replacing "
|
| 32 |
-
"an already imported distutils is deprecated. In the future, "
|
| 33 |
-
"this condition will fail. "
|
| 34 |
-
f"Register concerns at {report_url}"
|
| 35 |
-
)
|
| 36 |
-
mods = [
|
| 37 |
-
name
|
| 38 |
-
for name in sys.modules
|
| 39 |
-
if name == "distutils" or name.startswith("distutils.")
|
| 40 |
-
]
|
| 41 |
-
for name in mods:
|
| 42 |
-
del sys.modules[name]
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
def enabled():
|
| 46 |
-
"""
|
| 47 |
-
Allow selection of distutils by environment variable.
|
| 48 |
-
"""
|
| 49 |
-
which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local')
|
| 50 |
-
if which == 'stdlib':
|
| 51 |
-
import warnings
|
| 52 |
-
|
| 53 |
-
warnings.warn(
|
| 54 |
-
"Reliance on distutils from stdlib is deprecated. Users "
|
| 55 |
-
"must rely on setuptools to provide the distutils module. "
|
| 56 |
-
"Avoid importing distutils or import setuptools first, "
|
| 57 |
-
"and avoid setting SETUPTOOLS_USE_DISTUTILS=stdlib. "
|
| 58 |
-
f"Register concerns at {report_url}"
|
| 59 |
-
)
|
| 60 |
-
return which == 'local'
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
def ensure_local_distutils():
|
| 64 |
-
import importlib
|
| 65 |
-
|
| 66 |
-
clear_distutils()
|
| 67 |
-
|
| 68 |
-
# With the DistutilsMetaFinder in place,
|
| 69 |
-
# perform an import to cause distutils to be
|
| 70 |
-
# loaded from setuptools._distutils. Ref #2906.
|
| 71 |
-
with shim():
|
| 72 |
-
importlib.import_module('distutils')
|
| 73 |
-
|
| 74 |
-
# check that submodules load as expected
|
| 75 |
-
core = importlib.import_module('distutils.core')
|
| 76 |
-
assert '_distutils' in core.__file__, core.__file__
|
| 77 |
-
assert 'setuptools._distutils.log' not in sys.modules
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
def do_override():
|
| 81 |
-
"""
|
| 82 |
-
Ensure that the local copy of distutils is preferred over stdlib.
|
| 83 |
-
|
| 84 |
-
See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
|
| 85 |
-
for more motivation.
|
| 86 |
-
"""
|
| 87 |
-
if enabled():
|
| 88 |
-
warn_distutils_present()
|
| 89 |
-
ensure_local_distutils()
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
class _TrivialRe:
|
| 93 |
-
def __init__(self, *patterns) -> None:
|
| 94 |
-
self._patterns = patterns
|
| 95 |
-
|
| 96 |
-
def match(self, string):
|
| 97 |
-
return all(pat in string for pat in self._patterns)
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
class DistutilsMetaFinder:
|
| 101 |
-
def find_spec(self, fullname, path, target=None):
|
| 102 |
-
# optimization: only consider top level modules and those
|
| 103 |
-
# found in the CPython test suite.
|
| 104 |
-
if path is not None and not fullname.startswith('test.'):
|
| 105 |
-
return None
|
| 106 |
-
|
| 107 |
-
method_name = 'spec_for_{fullname}'.format(**locals())
|
| 108 |
-
method = getattr(self, method_name, lambda: None)
|
| 109 |
-
return method()
|
| 110 |
-
|
| 111 |
-
def spec_for_distutils(self):
|
| 112 |
-
if self.is_cpython():
|
| 113 |
-
return None
|
| 114 |
-
|
| 115 |
-
import importlib
|
| 116 |
-
import importlib.abc
|
| 117 |
-
import importlib.util
|
| 118 |
-
|
| 119 |
-
try:
|
| 120 |
-
mod = importlib.import_module('setuptools._distutils')
|
| 121 |
-
except Exception:
|
| 122 |
-
# There are a couple of cases where setuptools._distutils
|
| 123 |
-
# may not be present:
|
| 124 |
-
# - An older Setuptools without a local distutils is
|
| 125 |
-
# taking precedence. Ref #2957.
|
| 126 |
-
# - Path manipulation during sitecustomize removes
|
| 127 |
-
# setuptools from the path but only after the hook
|
| 128 |
-
# has been loaded. Ref #2980.
|
| 129 |
-
# In either case, fall back to stdlib behavior.
|
| 130 |
-
return None
|
| 131 |
-
|
| 132 |
-
class DistutilsLoader(importlib.abc.Loader):
|
| 133 |
-
def create_module(self, spec):
|
| 134 |
-
mod.__name__ = 'distutils'
|
| 135 |
-
return mod
|
| 136 |
-
|
| 137 |
-
def exec_module(self, module):
|
| 138 |
-
pass
|
| 139 |
-
|
| 140 |
-
return importlib.util.spec_from_loader(
|
| 141 |
-
'distutils', DistutilsLoader(), origin=mod.__file__
|
| 142 |
-
)
|
| 143 |
-
|
| 144 |
-
@staticmethod
|
| 145 |
-
def is_cpython():
|
| 146 |
-
"""
|
| 147 |
-
Suppress supplying distutils for CPython (build and tests).
|
| 148 |
-
Ref #2965 and #3007.
|
| 149 |
-
"""
|
| 150 |
-
return os.path.isfile('pybuilddir.txt')
|
| 151 |
-
|
| 152 |
-
def spec_for_pip(self):
|
| 153 |
-
"""
|
| 154 |
-
Ensure stdlib distutils when running under pip.
|
| 155 |
-
See pypa/pip#8761 for rationale.
|
| 156 |
-
"""
|
| 157 |
-
if sys.version_info >= (3, 12) or self.pip_imported_during_build():
|
| 158 |
-
return
|
| 159 |
-
clear_distutils()
|
| 160 |
-
self.spec_for_distutils = lambda: None
|
| 161 |
-
|
| 162 |
-
@classmethod
|
| 163 |
-
def pip_imported_during_build(cls):
|
| 164 |
-
"""
|
| 165 |
-
Detect if pip is being imported in a build script. Ref #2355.
|
| 166 |
-
"""
|
| 167 |
-
import traceback
|
| 168 |
-
|
| 169 |
-
return any(
|
| 170 |
-
cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None)
|
| 171 |
-
)
|
| 172 |
-
|
| 173 |
-
@staticmethod
|
| 174 |
-
def frame_file_is_setup(frame):
|
| 175 |
-
"""
|
| 176 |
-
Return True if the indicated frame suggests a setup.py file.
|
| 177 |
-
"""
|
| 178 |
-
# some frames may not have __file__ (#2940)
|
| 179 |
-
return frame.f_globals.get('__file__', '').endswith('setup.py')
|
| 180 |
-
|
| 181 |
-
def spec_for_sensitive_tests(self):
|
| 182 |
-
"""
|
| 183 |
-
Ensure stdlib distutils when running select tests under CPython.
|
| 184 |
-
|
| 185 |
-
python/cpython#91169
|
| 186 |
-
"""
|
| 187 |
-
clear_distutils()
|
| 188 |
-
self.spec_for_distutils = lambda: None
|
| 189 |
-
|
| 190 |
-
sensitive_tests = (
|
| 191 |
-
[
|
| 192 |
-
'test.test_distutils',
|
| 193 |
-
'test.test_peg_generator',
|
| 194 |
-
'test.test_importlib',
|
| 195 |
-
]
|
| 196 |
-
if sys.version_info < (3, 10)
|
| 197 |
-
else [
|
| 198 |
-
'test.test_distutils',
|
| 199 |
-
]
|
| 200 |
-
)
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
for name in DistutilsMetaFinder.sensitive_tests:
|
| 204 |
-
setattr(
|
| 205 |
-
DistutilsMetaFinder,
|
| 206 |
-
f'spec_for_{name}',
|
| 207 |
-
DistutilsMetaFinder.spec_for_sensitive_tests,
|
| 208 |
-
)
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
DISTUTILS_FINDER = DistutilsMetaFinder()
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
def add_shim():
|
| 215 |
-
DISTUTILS_FINDER in sys.meta_path or insert_shim()
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
class shim:
|
| 219 |
-
def __enter__(self) -> None:
|
| 220 |
-
insert_shim()
|
| 221 |
-
|
| 222 |
-
def __exit__(self, exc: object, value: object, tb: object) -> None:
|
| 223 |
-
_remove_shim()
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
def insert_shim():
|
| 227 |
-
sys.meta_path.insert(0, DISTUTILS_FINDER)
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
def _remove_shim():
|
| 231 |
-
try:
|
| 232 |
-
sys.meta_path.remove(DISTUTILS_FINDER)
|
| 233 |
-
except ValueError:
|
| 234 |
-
pass
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
if sys.version_info < (3, 12):
|
| 238 |
-
# DistutilsMetaFinder can only be disabled in Python < 3.12 (PEP 632)
|
| 239 |
-
remove_shim = _remove_shim
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_distutils_hack/override.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
__import__('_distutils_hack').do_override()
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_pytest/__init__.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
__all__ = ["__version__", "version_tuple"]
|
| 5 |
-
|
| 6 |
-
try:
|
| 7 |
-
from ._version import version as __version__
|
| 8 |
-
from ._version import version_tuple
|
| 9 |
-
except ImportError: # pragma: no cover
|
| 10 |
-
# broken installation, we don't even try
|
| 11 |
-
# unknown only works because we do poor mans version compare
|
| 12 |
-
__version__ = "unknown"
|
| 13 |
-
version_tuple = (0, 0, "unknown")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_pytest/_argcomplete.py
DELETED
|
@@ -1,117 +0,0 @@
|
|
| 1 |
-
"""Allow bash-completion for argparse with argcomplete if installed.
|
| 2 |
-
|
| 3 |
-
Needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
|
| 4 |
-
to find the magic string, so _ARGCOMPLETE env. var is never set, and
|
| 5 |
-
this does not need special code).
|
| 6 |
-
|
| 7 |
-
Function try_argcomplete(parser) should be called directly before
|
| 8 |
-
the call to ArgumentParser.parse_args().
|
| 9 |
-
|
| 10 |
-
The filescompleter is what you normally would use on the positional
|
| 11 |
-
arguments specification, in order to get "dirname/" after "dirn<TAB>"
|
| 12 |
-
instead of the default "dirname ":
|
| 13 |
-
|
| 14 |
-
optparser.add_argument(Config._file_or_dir, nargs='*').completer=filescompleter
|
| 15 |
-
|
| 16 |
-
Other, application specific, completers should go in the file
|
| 17 |
-
doing the add_argument calls as they need to be specified as .completer
|
| 18 |
-
attributes as well. (If argcomplete is not installed, the function the
|
| 19 |
-
attribute points to will not be used).
|
| 20 |
-
|
| 21 |
-
SPEEDUP
|
| 22 |
-
=======
|
| 23 |
-
|
| 24 |
-
The generic argcomplete script for bash-completion
|
| 25 |
-
(/etc/bash_completion.d/python-argcomplete.sh)
|
| 26 |
-
uses a python program to determine startup script generated by pip.
|
| 27 |
-
You can speed up completion somewhat by changing this script to include
|
| 28 |
-
# PYTHON_ARGCOMPLETE_OK
|
| 29 |
-
so the python-argcomplete-check-easy-install-script does not
|
| 30 |
-
need to be called to find the entry point of the code and see if that is
|
| 31 |
-
marked with PYTHON_ARGCOMPLETE_OK.
|
| 32 |
-
|
| 33 |
-
INSTALL/DEBUGGING
|
| 34 |
-
=================
|
| 35 |
-
|
| 36 |
-
To include this support in another application that has setup.py generated
|
| 37 |
-
scripts:
|
| 38 |
-
|
| 39 |
-
- Add the line:
|
| 40 |
-
# PYTHON_ARGCOMPLETE_OK
|
| 41 |
-
near the top of the main python entry point.
|
| 42 |
-
|
| 43 |
-
- Include in the file calling parse_args():
|
| 44 |
-
from _argcomplete import try_argcomplete, filescompleter
|
| 45 |
-
Call try_argcomplete just before parse_args(), and optionally add
|
| 46 |
-
filescompleter to the positional arguments' add_argument().
|
| 47 |
-
|
| 48 |
-
If things do not work right away:
|
| 49 |
-
|
| 50 |
-
- Switch on argcomplete debugging with (also helpful when doing custom
|
| 51 |
-
completers):
|
| 52 |
-
export _ARC_DEBUG=1
|
| 53 |
-
|
| 54 |
-
- Run:
|
| 55 |
-
python-argcomplete-check-easy-install-script $(which appname)
|
| 56 |
-
echo $?
|
| 57 |
-
will echo 0 if the magic line has been found, 1 if not.
|
| 58 |
-
|
| 59 |
-
- Sometimes it helps to find early on errors using:
|
| 60 |
-
_ARGCOMPLETE=1 _ARC_DEBUG=1 appname
|
| 61 |
-
which should throw a KeyError: 'COMPLINE' (which is properly set by the
|
| 62 |
-
global argcomplete script).
|
| 63 |
-
"""
|
| 64 |
-
|
| 65 |
-
from __future__ import annotations
|
| 66 |
-
|
| 67 |
-
import argparse
|
| 68 |
-
from glob import glob
|
| 69 |
-
import os
|
| 70 |
-
import sys
|
| 71 |
-
from typing import Any
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
class FastFilesCompleter:
|
| 75 |
-
"""Fast file completer class."""
|
| 76 |
-
|
| 77 |
-
def __init__(self, directories: bool = True) -> None:
|
| 78 |
-
self.directories = directories
|
| 79 |
-
|
| 80 |
-
def __call__(self, prefix: str, **kwargs: Any) -> list[str]:
|
| 81 |
-
# Only called on non option completions.
|
| 82 |
-
if os.sep in prefix[1:]:
|
| 83 |
-
prefix_dir = len(os.path.dirname(prefix) + os.sep)
|
| 84 |
-
else:
|
| 85 |
-
prefix_dir = 0
|
| 86 |
-
completion = []
|
| 87 |
-
globbed = []
|
| 88 |
-
if "*" not in prefix and "?" not in prefix:
|
| 89 |
-
# We are on unix, otherwise no bash.
|
| 90 |
-
if not prefix or prefix[-1] == os.sep:
|
| 91 |
-
globbed.extend(glob(prefix + ".*"))
|
| 92 |
-
prefix += "*"
|
| 93 |
-
globbed.extend(glob(prefix))
|
| 94 |
-
for x in sorted(globbed):
|
| 95 |
-
if os.path.isdir(x):
|
| 96 |
-
x += "/"
|
| 97 |
-
# Append stripping the prefix (like bash, not like compgen).
|
| 98 |
-
completion.append(x[prefix_dir:])
|
| 99 |
-
return completion
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
if os.environ.get("_ARGCOMPLETE"):
|
| 103 |
-
try:
|
| 104 |
-
import argcomplete.completers
|
| 105 |
-
except ImportError:
|
| 106 |
-
sys.exit(-1)
|
| 107 |
-
filescompleter: FastFilesCompleter | None = FastFilesCompleter()
|
| 108 |
-
|
| 109 |
-
def try_argcomplete(parser: argparse.ArgumentParser) -> None:
|
| 110 |
-
argcomplete.autocomplete(parser, always_complete_options=False)
|
| 111 |
-
|
| 112 |
-
else:
|
| 113 |
-
|
| 114 |
-
def try_argcomplete(parser: argparse.ArgumentParser) -> None:
|
| 115 |
-
pass
|
| 116 |
-
|
| 117 |
-
filescompleter = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_pytest/_code/__init__.py
DELETED
|
@@ -1,26 +0,0 @@
|
|
| 1 |
-
"""Python inspection/code generation API."""
|
| 2 |
-
|
| 3 |
-
from __future__ import annotations
|
| 4 |
-
|
| 5 |
-
from .code import Code
|
| 6 |
-
from .code import ExceptionInfo
|
| 7 |
-
from .code import filter_traceback
|
| 8 |
-
from .code import Frame
|
| 9 |
-
from .code import getfslineno
|
| 10 |
-
from .code import Traceback
|
| 11 |
-
from .code import TracebackEntry
|
| 12 |
-
from .source import getrawcode
|
| 13 |
-
from .source import Source
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
__all__ = [
|
| 17 |
-
"Code",
|
| 18 |
-
"ExceptionInfo",
|
| 19 |
-
"Frame",
|
| 20 |
-
"Source",
|
| 21 |
-
"Traceback",
|
| 22 |
-
"TracebackEntry",
|
| 23 |
-
"filter_traceback",
|
| 24 |
-
"getfslineno",
|
| 25 |
-
"getrawcode",
|
| 26 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_pytest/_code/code.py
DELETED
|
@@ -1,1632 +0,0 @@
|
|
| 1 |
-
# mypy: allow-untyped-defs
|
| 2 |
-
from __future__ import annotations
|
| 3 |
-
|
| 4 |
-
import ast
|
| 5 |
-
from collections.abc import Callable
|
| 6 |
-
from collections.abc import Iterable
|
| 7 |
-
from collections.abc import Mapping
|
| 8 |
-
from collections.abc import Sequence
|
| 9 |
-
import dataclasses
|
| 10 |
-
import inspect
|
| 11 |
-
from io import StringIO
|
| 12 |
-
import os
|
| 13 |
-
from pathlib import Path
|
| 14 |
-
import re
|
| 15 |
-
import sys
|
| 16 |
-
from traceback import extract_tb
|
| 17 |
-
from traceback import format_exception
|
| 18 |
-
from traceback import format_exception_only
|
| 19 |
-
from traceback import FrameSummary
|
| 20 |
-
from types import CodeType
|
| 21 |
-
from types import FrameType
|
| 22 |
-
from types import TracebackType
|
| 23 |
-
from typing import Any
|
| 24 |
-
from typing import ClassVar
|
| 25 |
-
from typing import Final
|
| 26 |
-
from typing import final
|
| 27 |
-
from typing import Generic
|
| 28 |
-
from typing import Literal
|
| 29 |
-
from typing import overload
|
| 30 |
-
from typing import SupportsIndex
|
| 31 |
-
from typing import TypeAlias
|
| 32 |
-
from typing import TypeVar
|
| 33 |
-
|
| 34 |
-
import pluggy
|
| 35 |
-
|
| 36 |
-
import _pytest
|
| 37 |
-
from _pytest._code.source import findsource
|
| 38 |
-
from _pytest._code.source import getrawcode
|
| 39 |
-
from _pytest._code.source import getstatementrange_ast
|
| 40 |
-
from _pytest._code.source import Source
|
| 41 |
-
from _pytest._io import TerminalWriter
|
| 42 |
-
from _pytest._io.saferepr import safeformat
|
| 43 |
-
from _pytest._io.saferepr import saferepr
|
| 44 |
-
from _pytest.compat import get_real_func
|
| 45 |
-
from _pytest.deprecated import check_ispytest
|
| 46 |
-
from _pytest.pathlib import absolutepath
|
| 47 |
-
from _pytest.pathlib import bestrelpath
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
if sys.version_info < (3, 11):
|
| 51 |
-
from exceptiongroup import BaseExceptionGroup
|
| 52 |
-
|
| 53 |
-
TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"]
|
| 54 |
-
|
| 55 |
-
EXCEPTION_OR_MORE = type[BaseException] | tuple[type[BaseException], ...]
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
class Code:
|
| 59 |
-
"""Wrapper around Python code objects."""
|
| 60 |
-
|
| 61 |
-
__slots__ = ("raw",)
|
| 62 |
-
|
| 63 |
-
def __init__(self, obj: CodeType) -> None:
|
| 64 |
-
self.raw = obj
|
| 65 |
-
|
| 66 |
-
@classmethod
|
| 67 |
-
def from_function(cls, obj: object) -> Code:
|
| 68 |
-
return cls(getrawcode(obj))
|
| 69 |
-
|
| 70 |
-
def __eq__(self, other):
|
| 71 |
-
return self.raw == other.raw
|
| 72 |
-
|
| 73 |
-
# Ignore type because of https://github.com/python/mypy/issues/4266.
|
| 74 |
-
__hash__ = None # type: ignore
|
| 75 |
-
|
| 76 |
-
@property
|
| 77 |
-
def firstlineno(self) -> int:
|
| 78 |
-
return self.raw.co_firstlineno - 1
|
| 79 |
-
|
| 80 |
-
@property
|
| 81 |
-
def name(self) -> str:
|
| 82 |
-
return self.raw.co_name
|
| 83 |
-
|
| 84 |
-
@property
|
| 85 |
-
def path(self) -> Path | str:
|
| 86 |
-
"""Return a path object pointing to source code, or an ``str`` in
|
| 87 |
-
case of ``OSError`` / non-existing file."""
|
| 88 |
-
filename = inspect.getfile(self.raw)
|
| 89 |
-
if not filename:
|
| 90 |
-
return ""
|
| 91 |
-
try:
|
| 92 |
-
p = absolutepath(filename)
|
| 93 |
-
# maybe don't try this checking
|
| 94 |
-
if not p.exists():
|
| 95 |
-
raise OSError("path check failed.")
|
| 96 |
-
return p
|
| 97 |
-
except OSError:
|
| 98 |
-
# XXX maybe try harder like the weird logic
|
| 99 |
-
# in the standard lib [linecache.updatecache] does?
|
| 100 |
-
return filename
|
| 101 |
-
|
| 102 |
-
@property
|
| 103 |
-
def fullsource(self) -> Source | None:
|
| 104 |
-
"""Return a _pytest._code.Source object for the full source file of the code."""
|
| 105 |
-
full, _ = findsource(self.raw)
|
| 106 |
-
return full
|
| 107 |
-
|
| 108 |
-
def source(self) -> Source:
|
| 109 |
-
"""Return a _pytest._code.Source object for the code object's source only."""
|
| 110 |
-
# return source only for that part of code
|
| 111 |
-
return Source(self.raw)
|
| 112 |
-
|
| 113 |
-
def getargs(self, var: bool = False) -> tuple[str, ...]:
|
| 114 |
-
"""Return a tuple with the argument names for the code object.
|
| 115 |
-
|
| 116 |
-
If 'var' is set True also return the names of the variable and
|
| 117 |
-
keyword arguments when present.
|
| 118 |
-
"""
|
| 119 |
-
# inspect.getargs merges positional and kwonly into a single list;
|
| 120 |
-
# co_argcount is needed to exclude kwonly when var=False.
|
| 121 |
-
args, varargs, varkw = inspect.getargs(self.raw)
|
| 122 |
-
if not var:
|
| 123 |
-
return tuple(args[: self.raw.co_argcount])
|
| 124 |
-
result = list(args)
|
| 125 |
-
if varargs is not None:
|
| 126 |
-
result.append(varargs)
|
| 127 |
-
if varkw is not None:
|
| 128 |
-
result.append(varkw)
|
| 129 |
-
return tuple(result)
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
class Frame:
|
| 133 |
-
"""Wrapper around a Python frame holding f_locals and f_globals
|
| 134 |
-
in which expressions can be evaluated."""
|
| 135 |
-
|
| 136 |
-
__slots__ = ("raw",)
|
| 137 |
-
|
| 138 |
-
def __init__(self, frame: FrameType) -> None:
|
| 139 |
-
self.raw = frame
|
| 140 |
-
|
| 141 |
-
@property
|
| 142 |
-
def lineno(self) -> int:
|
| 143 |
-
return self.raw.f_lineno - 1
|
| 144 |
-
|
| 145 |
-
@property
|
| 146 |
-
def f_globals(self) -> dict[str, Any]:
|
| 147 |
-
return self.raw.f_globals
|
| 148 |
-
|
| 149 |
-
@property
|
| 150 |
-
def f_locals(self) -> dict[str, Any]:
|
| 151 |
-
return self.raw.f_locals
|
| 152 |
-
|
| 153 |
-
@property
|
| 154 |
-
def code(self) -> Code:
|
| 155 |
-
return Code(self.raw.f_code)
|
| 156 |
-
|
| 157 |
-
@property
|
| 158 |
-
def statement(self) -> Source:
|
| 159 |
-
"""Statement this frame is at."""
|
| 160 |
-
if self.code.fullsource is None:
|
| 161 |
-
return Source("")
|
| 162 |
-
return self.code.fullsource.getstatement(self.lineno)
|
| 163 |
-
|
| 164 |
-
def eval(self, code, **vars):
|
| 165 |
-
"""Evaluate 'code' in the frame.
|
| 166 |
-
|
| 167 |
-
'vars' are optional additional local variables.
|
| 168 |
-
|
| 169 |
-
Returns the result of the evaluation.
|
| 170 |
-
"""
|
| 171 |
-
f_locals = self.f_locals.copy()
|
| 172 |
-
f_locals.update(vars)
|
| 173 |
-
return eval(code, self.f_globals, f_locals)
|
| 174 |
-
|
| 175 |
-
def repr(self, object: object) -> str:
|
| 176 |
-
"""Return a 'safe' (non-recursive, one-line) string repr for 'object'."""
|
| 177 |
-
return saferepr(object)
|
| 178 |
-
|
| 179 |
-
def getargs(self, var: bool = False):
|
| 180 |
-
"""Return a list of tuples (name, value) for all arguments.
|
| 181 |
-
|
| 182 |
-
If 'var' is set True, also include the variable and keyword arguments
|
| 183 |
-
when present.
|
| 184 |
-
"""
|
| 185 |
-
retval = []
|
| 186 |
-
for arg in self.code.getargs(var):
|
| 187 |
-
try:
|
| 188 |
-
retval.append((arg, self.f_locals[arg]))
|
| 189 |
-
except KeyError:
|
| 190 |
-
pass # this can occur when using Psyco
|
| 191 |
-
return retval
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
class TracebackEntry:
|
| 195 |
-
"""A single entry in a Traceback."""
|
| 196 |
-
|
| 197 |
-
__slots__ = ("_rawentry", "_repr_style")
|
| 198 |
-
|
| 199 |
-
def __init__(
|
| 200 |
-
self,
|
| 201 |
-
rawentry: TracebackType,
|
| 202 |
-
repr_style: Literal["short", "long"] | None = None,
|
| 203 |
-
) -> None:
|
| 204 |
-
self._rawentry: Final = rawentry
|
| 205 |
-
self._repr_style: Final = repr_style
|
| 206 |
-
|
| 207 |
-
def with_repr_style(
|
| 208 |
-
self, repr_style: Literal["short", "long"] | None
|
| 209 |
-
) -> TracebackEntry:
|
| 210 |
-
return TracebackEntry(self._rawentry, repr_style)
|
| 211 |
-
|
| 212 |
-
@property
|
| 213 |
-
def lineno(self) -> int:
|
| 214 |
-
return self._rawentry.tb_lineno - 1
|
| 215 |
-
|
| 216 |
-
def get_python_framesummary(self) -> FrameSummary:
|
| 217 |
-
# Python's built-in traceback module implements all the nitty gritty
|
| 218 |
-
# details to get column numbers of out frames.
|
| 219 |
-
stack_summary = extract_tb(self._rawentry, limit=1)
|
| 220 |
-
return stack_summary[0]
|
| 221 |
-
|
| 222 |
-
# Column and end line numbers introduced in python 3.11
|
| 223 |
-
if sys.version_info < (3, 11):
|
| 224 |
-
|
| 225 |
-
@property
|
| 226 |
-
def end_lineno_relative(self) -> int | None:
|
| 227 |
-
return None
|
| 228 |
-
|
| 229 |
-
@property
|
| 230 |
-
def colno(self) -> int | None:
|
| 231 |
-
return None
|
| 232 |
-
|
| 233 |
-
@property
|
| 234 |
-
def end_colno(self) -> int | None:
|
| 235 |
-
return None
|
| 236 |
-
else:
|
| 237 |
-
|
| 238 |
-
@property
|
| 239 |
-
def end_lineno_relative(self) -> int | None:
|
| 240 |
-
frame_summary = self.get_python_framesummary()
|
| 241 |
-
if frame_summary.end_lineno is None: # pragma: no cover
|
| 242 |
-
return None
|
| 243 |
-
return frame_summary.end_lineno - 1 - self.frame.code.firstlineno
|
| 244 |
-
|
| 245 |
-
@property
|
| 246 |
-
def colno(self) -> int | None:
|
| 247 |
-
"""Starting byte offset of the expression in the traceback entry."""
|
| 248 |
-
return self.get_python_framesummary().colno
|
| 249 |
-
|
| 250 |
-
@property
|
| 251 |
-
def end_colno(self) -> int | None:
|
| 252 |
-
"""Ending byte offset of the expression in the traceback entry."""
|
| 253 |
-
return self.get_python_framesummary().end_colno
|
| 254 |
-
|
| 255 |
-
@property
|
| 256 |
-
def frame(self) -> Frame:
|
| 257 |
-
return Frame(self._rawentry.tb_frame)
|
| 258 |
-
|
| 259 |
-
@property
|
| 260 |
-
def relline(self) -> int:
|
| 261 |
-
return self.lineno - self.frame.code.firstlineno
|
| 262 |
-
|
| 263 |
-
def __repr__(self) -> str:
|
| 264 |
-
return f"<TracebackEntry {self.frame.code.path}:{self.lineno + 1}>"
|
| 265 |
-
|
| 266 |
-
@property
|
| 267 |
-
def statement(self) -> Source:
|
| 268 |
-
"""_pytest._code.Source object for the current statement."""
|
| 269 |
-
source = self.frame.code.fullsource
|
| 270 |
-
assert source is not None
|
| 271 |
-
return source.getstatement(self.lineno)
|
| 272 |
-
|
| 273 |
-
@property
|
| 274 |
-
def path(self) -> Path | str:
|
| 275 |
-
"""Path to the source code."""
|
| 276 |
-
return self.frame.code.path
|
| 277 |
-
|
| 278 |
-
@property
|
| 279 |
-
def locals(self) -> dict[str, Any]:
|
| 280 |
-
"""Locals of underlying frame."""
|
| 281 |
-
return self.frame.f_locals
|
| 282 |
-
|
| 283 |
-
def getfirstlinesource(self) -> int:
|
| 284 |
-
return self.frame.code.firstlineno
|
| 285 |
-
|
| 286 |
-
def getsource(
|
| 287 |
-
self, astcache: dict[str | Path, ast.AST] | None = None
|
| 288 |
-
) -> Source | None:
|
| 289 |
-
"""Return failing source code."""
|
| 290 |
-
# we use the passed in astcache to not reparse asttrees
|
| 291 |
-
# within exception info printing
|
| 292 |
-
source = self.frame.code.fullsource
|
| 293 |
-
if source is None:
|
| 294 |
-
return None
|
| 295 |
-
key = astnode = None
|
| 296 |
-
if astcache is not None:
|
| 297 |
-
key = self.frame.code.path
|
| 298 |
-
if key is not None:
|
| 299 |
-
astnode = astcache.get(key, None)
|
| 300 |
-
start = self.getfirstlinesource()
|
| 301 |
-
try:
|
| 302 |
-
astnode, _, end = getstatementrange_ast(
|
| 303 |
-
self.lineno, source, astnode=astnode
|
| 304 |
-
)
|
| 305 |
-
except SyntaxError:
|
| 306 |
-
end = self.lineno + 1
|
| 307 |
-
else:
|
| 308 |
-
if key is not None and astcache is not None:
|
| 309 |
-
astcache[key] = astnode
|
| 310 |
-
return source[start:end]
|
| 311 |
-
|
| 312 |
-
source = property(getsource)
|
| 313 |
-
|
| 314 |
-
def ishidden(self, excinfo: ExceptionInfo[BaseException] | None) -> bool:
|
| 315 |
-
"""Return True if the current frame has a var __tracebackhide__
|
| 316 |
-
resolving to True.
|
| 317 |
-
|
| 318 |
-
If __tracebackhide__ is a callable, it gets called with the
|
| 319 |
-
ExceptionInfo instance and can decide whether to hide the traceback.
|
| 320 |
-
|
| 321 |
-
Mostly for internal use.
|
| 322 |
-
"""
|
| 323 |
-
tbh: bool | Callable[[ExceptionInfo[BaseException] | None], bool] = False
|
| 324 |
-
for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals):
|
| 325 |
-
# in normal cases, f_locals and f_globals are dictionaries
|
| 326 |
-
# however via `exec(...)` / `eval(...)` they can be other types
|
| 327 |
-
# (even incorrect types!).
|
| 328 |
-
# as such, we suppress all exceptions while accessing __tracebackhide__
|
| 329 |
-
try:
|
| 330 |
-
tbh = maybe_ns_dct["__tracebackhide__"]
|
| 331 |
-
except Exception:
|
| 332 |
-
pass
|
| 333 |
-
else:
|
| 334 |
-
break
|
| 335 |
-
if tbh and callable(tbh):
|
| 336 |
-
return tbh(excinfo)
|
| 337 |
-
return tbh
|
| 338 |
-
|
| 339 |
-
def __str__(self) -> str:
|
| 340 |
-
name = self.frame.code.name
|
| 341 |
-
try:
|
| 342 |
-
line = str(self.statement).lstrip()
|
| 343 |
-
except KeyboardInterrupt:
|
| 344 |
-
raise
|
| 345 |
-
except BaseException:
|
| 346 |
-
line = "???"
|
| 347 |
-
# This output does not quite match Python's repr for traceback entries,
|
| 348 |
-
# but changing it to do so would break certain plugins. See
|
| 349 |
-
# https://github.com/pytest-dev/pytest/pull/7535/ for details.
|
| 350 |
-
return f" File '{self.path}':{self.lineno + 1} in {name}\n {line}\n"
|
| 351 |
-
|
| 352 |
-
@property
|
| 353 |
-
def name(self) -> str:
|
| 354 |
-
"""co_name of underlying code."""
|
| 355 |
-
return self.frame.code.raw.co_name
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
class Traceback(list[TracebackEntry]):
|
| 359 |
-
"""Traceback objects encapsulate and offer higher level access to Traceback entries."""
|
| 360 |
-
|
| 361 |
-
def __init__(
|
| 362 |
-
self,
|
| 363 |
-
tb: TracebackType | Iterable[TracebackEntry],
|
| 364 |
-
) -> None:
|
| 365 |
-
"""Initialize from given python traceback object and ExceptionInfo."""
|
| 366 |
-
if isinstance(tb, TracebackType):
|
| 367 |
-
|
| 368 |
-
def f(cur: TracebackType) -> Iterable[TracebackEntry]:
|
| 369 |
-
cur_: TracebackType | None = cur
|
| 370 |
-
while cur_ is not None:
|
| 371 |
-
yield TracebackEntry(cur_)
|
| 372 |
-
cur_ = cur_.tb_next
|
| 373 |
-
|
| 374 |
-
super().__init__(f(tb))
|
| 375 |
-
else:
|
| 376 |
-
super().__init__(tb)
|
| 377 |
-
|
| 378 |
-
def cut(
|
| 379 |
-
self,
|
| 380 |
-
path: os.PathLike[str] | str | None = None,
|
| 381 |
-
lineno: int | None = None,
|
| 382 |
-
firstlineno: int | None = None,
|
| 383 |
-
excludepath: os.PathLike[str] | None = None,
|
| 384 |
-
) -> Traceback:
|
| 385 |
-
"""Return a Traceback instance wrapping part of this Traceback.
|
| 386 |
-
|
| 387 |
-
By providing any combination of path, lineno and firstlineno, the
|
| 388 |
-
first frame to start the to-be-returned traceback is determined.
|
| 389 |
-
|
| 390 |
-
This allows cutting the first part of a Traceback instance e.g.
|
| 391 |
-
for formatting reasons (removing some uninteresting bits that deal
|
| 392 |
-
with handling of the exception/traceback).
|
| 393 |
-
"""
|
| 394 |
-
path_ = None if path is None else os.fspath(path)
|
| 395 |
-
excludepath_ = None if excludepath is None else os.fspath(excludepath)
|
| 396 |
-
for x in self:
|
| 397 |
-
code = x.frame.code
|
| 398 |
-
codepath = code.path
|
| 399 |
-
if path is not None and str(codepath) != path_:
|
| 400 |
-
continue
|
| 401 |
-
if (
|
| 402 |
-
excludepath is not None
|
| 403 |
-
and isinstance(codepath, Path)
|
| 404 |
-
and excludepath_ in (str(p) for p in codepath.parents) # type: ignore[operator]
|
| 405 |
-
):
|
| 406 |
-
continue
|
| 407 |
-
if lineno is not None and x.lineno != lineno:
|
| 408 |
-
continue
|
| 409 |
-
if firstlineno is not None and x.frame.code.firstlineno != firstlineno:
|
| 410 |
-
continue
|
| 411 |
-
return Traceback(x._rawentry)
|
| 412 |
-
return self
|
| 413 |
-
|
| 414 |
-
@overload
|
| 415 |
-
def __getitem__(self, key: SupportsIndex) -> TracebackEntry: ...
|
| 416 |
-
|
| 417 |
-
@overload
|
| 418 |
-
def __getitem__(self, key: slice) -> Traceback: ...
|
| 419 |
-
|
| 420 |
-
def __getitem__(self, key: SupportsIndex | slice) -> TracebackEntry | Traceback:
|
| 421 |
-
if isinstance(key, slice):
|
| 422 |
-
return self.__class__(super().__getitem__(key))
|
| 423 |
-
else:
|
| 424 |
-
return super().__getitem__(key)
|
| 425 |
-
|
| 426 |
-
def filter(
|
| 427 |
-
self,
|
| 428 |
-
excinfo_or_fn: ExceptionInfo[BaseException] | Callable[[TracebackEntry], bool],
|
| 429 |
-
/,
|
| 430 |
-
) -> Traceback:
|
| 431 |
-
"""Return a Traceback instance with certain items removed.
|
| 432 |
-
|
| 433 |
-
If the filter is an `ExceptionInfo`, removes all the ``TracebackEntry``s
|
| 434 |
-
which are hidden (see ishidden() above).
|
| 435 |
-
|
| 436 |
-
Otherwise, the filter is a function that gets a single argument, a
|
| 437 |
-
``TracebackEntry`` instance, and should return True when the item should
|
| 438 |
-
be added to the ``Traceback``, False when not.
|
| 439 |
-
"""
|
| 440 |
-
if isinstance(excinfo_or_fn, ExceptionInfo):
|
| 441 |
-
fn = lambda x: not x.ishidden(excinfo_or_fn) # noqa: E731
|
| 442 |
-
else:
|
| 443 |
-
fn = excinfo_or_fn
|
| 444 |
-
return Traceback(filter(fn, self))
|
| 445 |
-
|
| 446 |
-
def recursionindex(self) -> int | None:
|
| 447 |
-
"""Return the index of the frame/TracebackEntry where recursion originates if
|
| 448 |
-
appropriate, None if no recursion occurred."""
|
| 449 |
-
cache: dict[tuple[Any, int, int], list[dict[str, Any]]] = {}
|
| 450 |
-
for i, entry in enumerate(self):
|
| 451 |
-
# id for the code.raw is needed to work around
|
| 452 |
-
# the strange metaprogramming in the decorator lib from pypi
|
| 453 |
-
# which generates code objects that have hash/value equality
|
| 454 |
-
# XXX needs a test
|
| 455 |
-
key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno
|
| 456 |
-
values = cache.setdefault(key, [])
|
| 457 |
-
# Since Python 3.13 f_locals is a proxy, freeze it.
|
| 458 |
-
loc = dict(entry.frame.f_locals)
|
| 459 |
-
if values:
|
| 460 |
-
for otherloc in values:
|
| 461 |
-
if otherloc == loc:
|
| 462 |
-
return i
|
| 463 |
-
values.append(loc)
|
| 464 |
-
return None
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
def stringify_exception(
|
| 468 |
-
exc: BaseException, include_subexception_msg: bool = True
|
| 469 |
-
) -> str:
|
| 470 |
-
try:
|
| 471 |
-
notes = getattr(exc, "__notes__", [])
|
| 472 |
-
except KeyError:
|
| 473 |
-
# Workaround for https://github.com/python/cpython/issues/98778 on
|
| 474 |
-
# some 3.10 and 3.11 patch versions.
|
| 475 |
-
HTTPError = getattr(sys.modules.get("urllib.error", None), "HTTPError", ())
|
| 476 |
-
if sys.version_info < (3, 12) and isinstance(exc, HTTPError):
|
| 477 |
-
notes = []
|
| 478 |
-
else: # pragma: no cover
|
| 479 |
-
# exception not related to above bug, reraise
|
| 480 |
-
raise
|
| 481 |
-
if not include_subexception_msg and isinstance(exc, BaseExceptionGroup):
|
| 482 |
-
message = exc.message
|
| 483 |
-
else:
|
| 484 |
-
message = str(exc)
|
| 485 |
-
|
| 486 |
-
return "\n".join(
|
| 487 |
-
[
|
| 488 |
-
message,
|
| 489 |
-
*notes,
|
| 490 |
-
]
|
| 491 |
-
)
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
E = TypeVar("E", bound=BaseException, covariant=True)
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
@final
|
| 498 |
-
@dataclasses.dataclass
|
| 499 |
-
class ExceptionInfo(Generic[E]):
|
| 500 |
-
"""Wraps sys.exc_info() objects and offers help for navigating the traceback."""
|
| 501 |
-
|
| 502 |
-
_assert_start_repr: ClassVar = "AssertionError('assert "
|
| 503 |
-
|
| 504 |
-
_excinfo: tuple[type[E], E, TracebackType] | None
|
| 505 |
-
_striptext: str
|
| 506 |
-
_traceback: Traceback | None
|
| 507 |
-
|
| 508 |
-
def __init__(
|
| 509 |
-
self,
|
| 510 |
-
excinfo: tuple[type[E], E, TracebackType] | None,
|
| 511 |
-
striptext: str = "",
|
| 512 |
-
traceback: Traceback | None = None,
|
| 513 |
-
*,
|
| 514 |
-
_ispytest: bool = False,
|
| 515 |
-
) -> None:
|
| 516 |
-
check_ispytest(_ispytest)
|
| 517 |
-
self._excinfo = excinfo
|
| 518 |
-
self._striptext = striptext
|
| 519 |
-
self._traceback = traceback
|
| 520 |
-
|
| 521 |
-
@classmethod
|
| 522 |
-
def from_exception(
|
| 523 |
-
cls,
|
| 524 |
-
# Ignoring error: "Cannot use a covariant type variable as a parameter".
|
| 525 |
-
# This is OK to ignore because this class is (conceptually) readonly.
|
| 526 |
-
# See https://github.com/python/mypy/issues/7049.
|
| 527 |
-
exception: E, # type: ignore[misc]
|
| 528 |
-
exprinfo: str | None = None,
|
| 529 |
-
) -> ExceptionInfo[E]:
|
| 530 |
-
"""Return an ExceptionInfo for an existing exception.
|
| 531 |
-
|
| 532 |
-
The exception must have a non-``None`` ``__traceback__`` attribute,
|
| 533 |
-
otherwise this function fails with an assertion error. This means that
|
| 534 |
-
the exception must have been raised, or added a traceback with the
|
| 535 |
-
:py:meth:`~BaseException.with_traceback()` method.
|
| 536 |
-
|
| 537 |
-
:param exprinfo:
|
| 538 |
-
A text string helping to determine if we should strip
|
| 539 |
-
``AssertionError`` from the output. Defaults to the exception
|
| 540 |
-
message/``__str__()``.
|
| 541 |
-
|
| 542 |
-
.. versionadded:: 7.4
|
| 543 |
-
"""
|
| 544 |
-
assert exception.__traceback__, (
|
| 545 |
-
"Exceptions passed to ExcInfo.from_exception(...)"
|
| 546 |
-
" must have a non-None __traceback__."
|
| 547 |
-
)
|
| 548 |
-
exc_info = (type(exception), exception, exception.__traceback__)
|
| 549 |
-
return cls.from_exc_info(exc_info, exprinfo)
|
| 550 |
-
|
| 551 |
-
@classmethod
|
| 552 |
-
def from_exc_info(
|
| 553 |
-
cls,
|
| 554 |
-
exc_info: tuple[type[E], E, TracebackType],
|
| 555 |
-
exprinfo: str | None = None,
|
| 556 |
-
) -> ExceptionInfo[E]:
|
| 557 |
-
"""Like :func:`from_exception`, but using old-style exc_info tuple."""
|
| 558 |
-
_striptext = ""
|
| 559 |
-
if exprinfo is None and isinstance(exc_info[1], AssertionError):
|
| 560 |
-
exprinfo = getattr(exc_info[1], "msg", None)
|
| 561 |
-
if exprinfo is None:
|
| 562 |
-
exprinfo = saferepr(exc_info[1])
|
| 563 |
-
if exprinfo and exprinfo.startswith(cls._assert_start_repr):
|
| 564 |
-
_striptext = "AssertionError: "
|
| 565 |
-
|
| 566 |
-
return cls(exc_info, _striptext, _ispytest=True)
|
| 567 |
-
|
| 568 |
-
@classmethod
|
| 569 |
-
def from_current(cls, exprinfo: str | None = None) -> ExceptionInfo[BaseException]:
|
| 570 |
-
"""Return an ExceptionInfo matching the current traceback.
|
| 571 |
-
|
| 572 |
-
.. warning::
|
| 573 |
-
|
| 574 |
-
Experimental API
|
| 575 |
-
|
| 576 |
-
:param exprinfo:
|
| 577 |
-
A text string helping to determine if we should strip
|
| 578 |
-
``AssertionError`` from the output. Defaults to the exception
|
| 579 |
-
message/``__str__()``.
|
| 580 |
-
"""
|
| 581 |
-
tup = sys.exc_info()
|
| 582 |
-
assert tup[0] is not None, "no current exception"
|
| 583 |
-
assert tup[1] is not None, "no current exception"
|
| 584 |
-
assert tup[2] is not None, "no current exception"
|
| 585 |
-
exc_info = (tup[0], tup[1], tup[2])
|
| 586 |
-
return ExceptionInfo.from_exc_info(exc_info, exprinfo)
|
| 587 |
-
|
| 588 |
-
@classmethod
|
| 589 |
-
def for_later(cls) -> ExceptionInfo[E]:
|
| 590 |
-
"""Return an unfilled ExceptionInfo."""
|
| 591 |
-
return cls(None, _ispytest=True)
|
| 592 |
-
|
| 593 |
-
def fill_unfilled(self, exc_info: tuple[type[E], E, TracebackType]) -> None:
|
| 594 |
-
"""Fill an unfilled ExceptionInfo created with ``for_later()``."""
|
| 595 |
-
assert self._excinfo is None, "ExceptionInfo was already filled"
|
| 596 |
-
self._excinfo = exc_info
|
| 597 |
-
|
| 598 |
-
@property
|
| 599 |
-
def type(self) -> type[E]:
|
| 600 |
-
"""The exception class."""
|
| 601 |
-
assert self._excinfo is not None, (
|
| 602 |
-
".type can only be used after the context manager exits"
|
| 603 |
-
)
|
| 604 |
-
return self._excinfo[0]
|
| 605 |
-
|
| 606 |
-
@property
|
| 607 |
-
def value(self) -> E:
|
| 608 |
-
"""The exception value."""
|
| 609 |
-
assert self._excinfo is not None, (
|
| 610 |
-
".value can only be used after the context manager exits"
|
| 611 |
-
)
|
| 612 |
-
return self._excinfo[1]
|
| 613 |
-
|
| 614 |
-
@property
|
| 615 |
-
def tb(self) -> TracebackType:
|
| 616 |
-
"""The exception raw traceback."""
|
| 617 |
-
assert self._excinfo is not None, (
|
| 618 |
-
".tb can only be used after the context manager exits"
|
| 619 |
-
)
|
| 620 |
-
return self._excinfo[2]
|
| 621 |
-
|
| 622 |
-
@property
|
| 623 |
-
def typename(self) -> str:
|
| 624 |
-
"""The type name of the exception."""
|
| 625 |
-
assert self._excinfo is not None, (
|
| 626 |
-
".typename can only be used after the context manager exits"
|
| 627 |
-
)
|
| 628 |
-
return self.type.__name__
|
| 629 |
-
|
| 630 |
-
@property
|
| 631 |
-
def traceback(self) -> Traceback:
|
| 632 |
-
"""The traceback."""
|
| 633 |
-
if self._traceback is None:
|
| 634 |
-
self._traceback = Traceback(self.tb)
|
| 635 |
-
return self._traceback
|
| 636 |
-
|
| 637 |
-
@traceback.setter
|
| 638 |
-
def traceback(self, value: Traceback) -> None:
|
| 639 |
-
self._traceback = value
|
| 640 |
-
|
| 641 |
-
def __repr__(self) -> str:
|
| 642 |
-
if self._excinfo is None:
|
| 643 |
-
return "<ExceptionInfo for raises contextmanager>"
|
| 644 |
-
return f"<{self.__class__.__name__} {saferepr(self._excinfo[1])} tblen={len(self.traceback)}>"
|
| 645 |
-
|
| 646 |
-
def exconly(self, tryshort: bool = False) -> str:
|
| 647 |
-
"""Return the exception as a string.
|
| 648 |
-
|
| 649 |
-
This is usually a single line "<exception type>: <exception str>", but
|
| 650 |
-
may also include additional lines for the exception notes, and detailed
|
| 651 |
-
information for SyntaxError's.
|
| 652 |
-
|
| 653 |
-
:param tryshort:
|
| 654 |
-
If true, and the exception is an AssertionError, strip
|
| 655 |
-
'AssertionError: ' from the beginning.
|
| 656 |
-
"""
|
| 657 |
-
|
| 658 |
-
def _get_single_subexc(
|
| 659 |
-
eg: BaseExceptionGroup[BaseException],
|
| 660 |
-
) -> BaseException | None:
|
| 661 |
-
if len(eg.exceptions) != 1:
|
| 662 |
-
return None
|
| 663 |
-
if isinstance(e := eg.exceptions[0], BaseExceptionGroup):
|
| 664 |
-
return _get_single_subexc(e)
|
| 665 |
-
return e
|
| 666 |
-
|
| 667 |
-
if (
|
| 668 |
-
tryshort
|
| 669 |
-
and isinstance(self.value, BaseExceptionGroup)
|
| 670 |
-
and (subexc := _get_single_subexc(self.value)) is not None
|
| 671 |
-
):
|
| 672 |
-
return f"{subexc!r} [single exception in {type(self.value).__name__}]"
|
| 673 |
-
|
| 674 |
-
lines = format_exception_only(self.value)
|
| 675 |
-
# The lines already include line separators.
|
| 676 |
-
text = "".join(lines)
|
| 677 |
-
text = text.rstrip()
|
| 678 |
-
if tryshort:
|
| 679 |
-
if text.startswith(self._striptext):
|
| 680 |
-
text = text[len(self._striptext) :]
|
| 681 |
-
return text
|
| 682 |
-
|
| 683 |
-
def errisinstance(self, exc: EXCEPTION_OR_MORE) -> bool:
|
| 684 |
-
"""Return True if the exception is an instance of exc.
|
| 685 |
-
|
| 686 |
-
Consider using ``isinstance(excinfo.value, exc)`` instead.
|
| 687 |
-
"""
|
| 688 |
-
return isinstance(self.value, exc)
|
| 689 |
-
|
| 690 |
-
def _getreprcrash(self) -> ReprFileLocation | None:
|
| 691 |
-
# Find last non-hidden traceback entry that led to the exception of the
|
| 692 |
-
# traceback, or None if all hidden.
|
| 693 |
-
for i in range(-1, -len(self.traceback) - 1, -1):
|
| 694 |
-
entry = self.traceback[i]
|
| 695 |
-
if not entry.ishidden(self):
|
| 696 |
-
path, lineno = entry.frame.code.raw.co_filename, entry.lineno
|
| 697 |
-
exconly = self.exconly(tryshort=True)
|
| 698 |
-
return ReprFileLocation(path, lineno + 1, exconly)
|
| 699 |
-
return None
|
| 700 |
-
|
| 701 |
-
def getrepr(
|
| 702 |
-
self,
|
| 703 |
-
showlocals: bool = False,
|
| 704 |
-
style: TracebackStyle = "long",
|
| 705 |
-
abspath: bool = False,
|
| 706 |
-
tbfilter: bool | Callable[[ExceptionInfo[BaseException]], Traceback] = True,
|
| 707 |
-
funcargs: bool = False,
|
| 708 |
-
truncate_locals: bool = True,
|
| 709 |
-
truncate_args: bool = True,
|
| 710 |
-
chain: bool = True,
|
| 711 |
-
) -> ReprExceptionInfo | ExceptionChainRepr:
|
| 712 |
-
"""Return str()able representation of this exception info.
|
| 713 |
-
|
| 714 |
-
The formatting parameters are ineffective if ``style="native"``,
|
| 715 |
-
since in this case the native formatting is used.
|
| 716 |
-
|
| 717 |
-
:param bool showlocals:
|
| 718 |
-
Show locals per traceback entry.
|
| 719 |
-
|
| 720 |
-
:param str style:
|
| 721 |
-
long|short|line|no|native|value traceback style.
|
| 722 |
-
|
| 723 |
-
:param bool abspath:
|
| 724 |
-
If paths should be changed to absolute or left unchanged.
|
| 725 |
-
|
| 726 |
-
:param tbfilter:
|
| 727 |
-
A filter for traceback entries.
|
| 728 |
-
|
| 729 |
-
* If false, don't hide any entries.
|
| 730 |
-
* If true, hide internal entries and entries that contain a local
|
| 731 |
-
variable ``__tracebackhide__ = True``.
|
| 732 |
-
* If a callable, delegates the filtering to the callable.
|
| 733 |
-
|
| 734 |
-
:param bool funcargs:
|
| 735 |
-
Show function arguments per traceback entry.
|
| 736 |
-
|
| 737 |
-
:param bool truncate_locals:
|
| 738 |
-
Whether to show a size-limited `repr()` of locals, or a full
|
| 739 |
-
pretty-printing.
|
| 740 |
-
|
| 741 |
-
:param bool truncate_args:
|
| 742 |
-
Whether to show a size-limited truncated `repr()` of function
|
| 743 |
-
arguments, or a full pretty-printing.
|
| 744 |
-
|
| 745 |
-
:param bool chain:
|
| 746 |
-
If chained exceptions should be shown.
|
| 747 |
-
|
| 748 |
-
.. versionchanged:: 3.9
|
| 749 |
-
|
| 750 |
-
Added the ``chain`` parameter.
|
| 751 |
-
"""
|
| 752 |
-
if style == "native":
|
| 753 |
-
return ReprExceptionInfo(
|
| 754 |
-
reprtraceback=ReprTracebackNative(
|
| 755 |
-
format_exception(
|
| 756 |
-
self.type,
|
| 757 |
-
self.value,
|
| 758 |
-
self.traceback[0]._rawentry if self.traceback else None,
|
| 759 |
-
)
|
| 760 |
-
),
|
| 761 |
-
reprcrash=self._getreprcrash(),
|
| 762 |
-
)
|
| 763 |
-
|
| 764 |
-
fmt = ExceptionInfoFormatter(
|
| 765 |
-
showlocals=showlocals,
|
| 766 |
-
style=style,
|
| 767 |
-
abspath=abspath,
|
| 768 |
-
tbfilter=tbfilter,
|
| 769 |
-
funcargs=funcargs,
|
| 770 |
-
truncate_locals=truncate_locals,
|
| 771 |
-
truncate_args=truncate_args,
|
| 772 |
-
chain=chain,
|
| 773 |
-
)
|
| 774 |
-
return fmt.repr_excinfo(self)
|
| 775 |
-
|
| 776 |
-
def match(self, regexp: str | re.Pattern[str]) -> Literal[True]:
|
| 777 |
-
"""Check whether the regular expression `regexp` matches the string
|
| 778 |
-
representation of the exception using :func:`python:re.search`.
|
| 779 |
-
|
| 780 |
-
If it matches `True` is returned, otherwise an `AssertionError` is raised.
|
| 781 |
-
"""
|
| 782 |
-
__tracebackhide__ = True
|
| 783 |
-
value = stringify_exception(self.value)
|
| 784 |
-
msg = (
|
| 785 |
-
f"Regex pattern did not match.\n"
|
| 786 |
-
f" Expected regex: {regexp!r}\n"
|
| 787 |
-
f" Actual message: {value!r}"
|
| 788 |
-
)
|
| 789 |
-
if regexp == value:
|
| 790 |
-
msg += "\n Did you mean to `re.escape()` the regex?"
|
| 791 |
-
assert re.search(regexp, value), msg
|
| 792 |
-
# Return True to allow for "assert excinfo.match()".
|
| 793 |
-
return True
|
| 794 |
-
|
| 795 |
-
def _group_contains(
|
| 796 |
-
self,
|
| 797 |
-
exc_group: BaseExceptionGroup[BaseException],
|
| 798 |
-
expected_exception: EXCEPTION_OR_MORE,
|
| 799 |
-
match: str | re.Pattern[str] | None,
|
| 800 |
-
target_depth: int | None = None,
|
| 801 |
-
current_depth: int = 1,
|
| 802 |
-
) -> bool:
|
| 803 |
-
"""Return `True` if a `BaseExceptionGroup` contains a matching exception."""
|
| 804 |
-
if (target_depth is not None) and (current_depth > target_depth):
|
| 805 |
-
# already descended past the target depth
|
| 806 |
-
return False
|
| 807 |
-
for exc in exc_group.exceptions:
|
| 808 |
-
if isinstance(exc, BaseExceptionGroup):
|
| 809 |
-
if self._group_contains(
|
| 810 |
-
exc, expected_exception, match, target_depth, current_depth + 1
|
| 811 |
-
):
|
| 812 |
-
return True
|
| 813 |
-
if (target_depth is not None) and (current_depth != target_depth):
|
| 814 |
-
# not at the target depth, no match
|
| 815 |
-
continue
|
| 816 |
-
if not isinstance(exc, expected_exception):
|
| 817 |
-
continue
|
| 818 |
-
if match is not None:
|
| 819 |
-
value = stringify_exception(exc)
|
| 820 |
-
if not re.search(match, value):
|
| 821 |
-
continue
|
| 822 |
-
return True
|
| 823 |
-
return False
|
| 824 |
-
|
| 825 |
-
def group_contains(
|
| 826 |
-
self,
|
| 827 |
-
expected_exception: EXCEPTION_OR_MORE,
|
| 828 |
-
*,
|
| 829 |
-
match: str | re.Pattern[str] | None = None,
|
| 830 |
-
depth: int | None = None,
|
| 831 |
-
) -> bool:
|
| 832 |
-
"""Check whether a captured exception group contains a matching exception.
|
| 833 |
-
|
| 834 |
-
:param Type[BaseException] | Tuple[Type[BaseException]] expected_exception:
|
| 835 |
-
The expected exception type, or a tuple if one of multiple possible
|
| 836 |
-
exception types are expected.
|
| 837 |
-
|
| 838 |
-
:param str | re.Pattern[str] | None match:
|
| 839 |
-
If specified, a string containing a regular expression,
|
| 840 |
-
or a regular expression object, that is tested against the string
|
| 841 |
-
representation of the exception and its `PEP-678 <https://peps.python.org/pep-0678/>` `__notes__`
|
| 842 |
-
using :func:`re.search`.
|
| 843 |
-
|
| 844 |
-
To match a literal string that may contain :ref:`special characters
|
| 845 |
-
<re-syntax>`, the pattern can first be escaped with :func:`re.escape`.
|
| 846 |
-
|
| 847 |
-
:param Optional[int] depth:
|
| 848 |
-
If `None`, will search for a matching exception at any nesting depth.
|
| 849 |
-
If >= 1, will only match an exception if it's at the specified depth (depth = 1 being
|
| 850 |
-
the exceptions contained within the topmost exception group).
|
| 851 |
-
|
| 852 |
-
.. versionadded:: 8.0
|
| 853 |
-
|
| 854 |
-
.. warning::
|
| 855 |
-
This helper makes it easy to check for the presence of specific exceptions,
|
| 856 |
-
but it is very bad for checking that the group does *not* contain
|
| 857 |
-
*any other exceptions*.
|
| 858 |
-
You should instead consider using :class:`pytest.RaisesGroup`
|
| 859 |
-
|
| 860 |
-
"""
|
| 861 |
-
msg = "Captured exception is not an instance of `BaseExceptionGroup`"
|
| 862 |
-
assert isinstance(self.value, BaseExceptionGroup), msg
|
| 863 |
-
msg = "`depth` must be >= 1 if specified"
|
| 864 |
-
assert (depth is None) or (depth >= 1), msg
|
| 865 |
-
return self._group_contains(self.value, expected_exception, match, depth)
|
| 866 |
-
|
| 867 |
-
|
| 868 |
-
# Type alias for the `tbfilter` setting:
|
| 869 |
-
# bool: If True, it should be filtered using Traceback.filter()
|
| 870 |
-
# callable: A callable that takes an ExceptionInfo and returns the filtered traceback.
|
| 871 |
-
TracebackFilter: TypeAlias = bool | Callable[[ExceptionInfo[BaseException]], Traceback]
|
| 872 |
-
|
| 873 |
-
|
| 874 |
-
@dataclasses.dataclass
|
| 875 |
-
class ExceptionInfoFormatter:
|
| 876 |
-
"""Helper object to format ExceptionInfo's and individual exception parts
|
| 877 |
-
into TerminalRepr's.
|
| 878 |
-
|
| 879 |
-
See :func:`ExceptionInfo.getrepr` for parameters.
|
| 880 |
-
"""
|
| 881 |
-
|
| 882 |
-
# for traceback entries
|
| 883 |
-
flow_marker: ClassVar = ">"
|
| 884 |
-
fail_marker: ClassVar = "E"
|
| 885 |
-
|
| 886 |
-
showlocals: bool = False
|
| 887 |
-
# Note: "native" is handled outside of ExceptionInfoFormatter.
|
| 888 |
-
style: TracebackStyle = "long"
|
| 889 |
-
abspath: bool = True
|
| 890 |
-
tbfilter: TracebackFilter = True
|
| 891 |
-
funcargs: bool = False
|
| 892 |
-
truncate_locals: bool = True
|
| 893 |
-
truncate_args: bool = True
|
| 894 |
-
chain: bool = True
|
| 895 |
-
|
| 896 |
-
astcache: dict[str | Path, ast.AST] = dataclasses.field(
|
| 897 |
-
default_factory=dict, init=False, repr=False
|
| 898 |
-
)
|
| 899 |
-
|
| 900 |
-
def _getindent(self, source: Source) -> int:
|
| 901 |
-
# Figure out indent for the given source.
|
| 902 |
-
try:
|
| 903 |
-
s = str(source.getstatement(len(source) - 1))
|
| 904 |
-
except KeyboardInterrupt:
|
| 905 |
-
raise
|
| 906 |
-
except BaseException:
|
| 907 |
-
try:
|
| 908 |
-
s = str(source[-1])
|
| 909 |
-
except KeyboardInterrupt:
|
| 910 |
-
raise
|
| 911 |
-
except BaseException:
|
| 912 |
-
return 0
|
| 913 |
-
return 4 + (len(s) - len(s.lstrip()))
|
| 914 |
-
|
| 915 |
-
def _getentrysource(self, entry: TracebackEntry) -> Source | None:
|
| 916 |
-
source = entry.getsource(self.astcache)
|
| 917 |
-
if source is not None:
|
| 918 |
-
source = source.deindent()
|
| 919 |
-
return source
|
| 920 |
-
|
| 921 |
-
def repr_args(self, entry: TracebackEntry) -> ReprFuncArgs | None:
|
| 922 |
-
if self.funcargs:
|
| 923 |
-
args = []
|
| 924 |
-
for argname, argvalue in entry.frame.getargs(var=True):
|
| 925 |
-
if self.truncate_args:
|
| 926 |
-
str_repr = saferepr(argvalue)
|
| 927 |
-
else:
|
| 928 |
-
str_repr = saferepr(argvalue, maxsize=None)
|
| 929 |
-
args.append((argname, str_repr))
|
| 930 |
-
return ReprFuncArgs(args)
|
| 931 |
-
return None
|
| 932 |
-
|
| 933 |
-
def get_source(
|
| 934 |
-
self,
|
| 935 |
-
source: Source | None,
|
| 936 |
-
line_index: int = -1,
|
| 937 |
-
excinfo: ExceptionInfo[BaseException] | None = None,
|
| 938 |
-
short: bool = False,
|
| 939 |
-
end_line_index: int | None = None,
|
| 940 |
-
colno: int | None = None,
|
| 941 |
-
end_colno: int | None = None,
|
| 942 |
-
) -> list[str]:
|
| 943 |
-
"""Return formatted and marked up source lines."""
|
| 944 |
-
lines = []
|
| 945 |
-
if source is not None and line_index < 0:
|
| 946 |
-
line_index += len(source)
|
| 947 |
-
if source is None or line_index >= len(source.lines) or line_index < 0:
|
| 948 |
-
# `line_index` could still be outside `range(len(source.lines))` if
|
| 949 |
-
# we're processing AST with pathological position attributes.
|
| 950 |
-
source = Source("???")
|
| 951 |
-
line_index = 0
|
| 952 |
-
space_prefix = " "
|
| 953 |
-
if short:
|
| 954 |
-
lines.append(space_prefix + source.lines[line_index].strip())
|
| 955 |
-
lines.extend(
|
| 956 |
-
self.get_highlight_arrows_for_line(
|
| 957 |
-
raw_line=source.raw_lines[line_index],
|
| 958 |
-
line=source.lines[line_index].strip(),
|
| 959 |
-
lineno=line_index,
|
| 960 |
-
end_lineno=end_line_index,
|
| 961 |
-
colno=colno,
|
| 962 |
-
end_colno=end_colno,
|
| 963 |
-
)
|
| 964 |
-
)
|
| 965 |
-
else:
|
| 966 |
-
for line in source.lines[:line_index]:
|
| 967 |
-
lines.append(space_prefix + line)
|
| 968 |
-
lines.append(self.flow_marker + " " + source.lines[line_index])
|
| 969 |
-
lines.extend(
|
| 970 |
-
self.get_highlight_arrows_for_line(
|
| 971 |
-
raw_line=source.raw_lines[line_index],
|
| 972 |
-
line=source.lines[line_index],
|
| 973 |
-
lineno=line_index,
|
| 974 |
-
end_lineno=end_line_index,
|
| 975 |
-
colno=colno,
|
| 976 |
-
end_colno=end_colno,
|
| 977 |
-
)
|
| 978 |
-
)
|
| 979 |
-
for line in source.lines[line_index + 1 :]:
|
| 980 |
-
lines.append(space_prefix + line)
|
| 981 |
-
if excinfo is not None:
|
| 982 |
-
indent = 4 if short else self._getindent(source)
|
| 983 |
-
lines.extend(self.get_exconly(excinfo, indent=indent, markall=True))
|
| 984 |
-
return lines
|
| 985 |
-
|
| 986 |
-
def get_highlight_arrows_for_line(
|
| 987 |
-
self,
|
| 988 |
-
line: str,
|
| 989 |
-
raw_line: str,
|
| 990 |
-
lineno: int | None,
|
| 991 |
-
end_lineno: int | None,
|
| 992 |
-
colno: int | None,
|
| 993 |
-
end_colno: int | None,
|
| 994 |
-
) -> list[str]:
|
| 995 |
-
"""Return characters highlighting a source line.
|
| 996 |
-
|
| 997 |
-
Example with colno and end_colno pointing to the bar expression:
|
| 998 |
-
"foo() + bar()"
|
| 999 |
-
returns " ^^^^^"
|
| 1000 |
-
"""
|
| 1001 |
-
if lineno != end_lineno:
|
| 1002 |
-
# Don't handle expressions that span multiple lines.
|
| 1003 |
-
return []
|
| 1004 |
-
if colno is None or end_colno is None:
|
| 1005 |
-
# Can't do anything without column information.
|
| 1006 |
-
return []
|
| 1007 |
-
|
| 1008 |
-
num_stripped_chars = len(raw_line) - len(line)
|
| 1009 |
-
|
| 1010 |
-
start_char_offset = _byte_offset_to_character_offset(raw_line, colno)
|
| 1011 |
-
end_char_offset = _byte_offset_to_character_offset(raw_line, end_colno)
|
| 1012 |
-
num_carets = end_char_offset - start_char_offset
|
| 1013 |
-
# If the highlight would span the whole line, it is redundant, don't
|
| 1014 |
-
# show it.
|
| 1015 |
-
if num_carets >= len(line.strip()):
|
| 1016 |
-
return []
|
| 1017 |
-
|
| 1018 |
-
highlights = " "
|
| 1019 |
-
highlights += " " * (start_char_offset - num_stripped_chars + 1)
|
| 1020 |
-
highlights += "^" * num_carets
|
| 1021 |
-
return [highlights]
|
| 1022 |
-
|
| 1023 |
-
def get_exconly(
|
| 1024 |
-
self,
|
| 1025 |
-
excinfo: ExceptionInfo[BaseException],
|
| 1026 |
-
indent: int = 4,
|
| 1027 |
-
markall: bool = False,
|
| 1028 |
-
) -> list[str]:
|
| 1029 |
-
lines = []
|
| 1030 |
-
indentstr = " " * indent
|
| 1031 |
-
# Get the real exception information out.
|
| 1032 |
-
exlines = excinfo.exconly(tryshort=True).split("\n")
|
| 1033 |
-
failindent = self.fail_marker + indentstr[1:]
|
| 1034 |
-
for line in exlines:
|
| 1035 |
-
lines.append(failindent + line)
|
| 1036 |
-
if not markall:
|
| 1037 |
-
failindent = indentstr
|
| 1038 |
-
return lines
|
| 1039 |
-
|
| 1040 |
-
def repr_locals(self, locals: Mapping[str, object]) -> ReprLocals | None:
|
| 1041 |
-
if self.showlocals:
|
| 1042 |
-
lines = []
|
| 1043 |
-
# Variables starting with `@` are helpers injected by assertion
|
| 1044 |
-
# rewriting, not user variables, so hide them.
|
| 1045 |
-
keys = [loc for loc in locals if loc[0] != "@"]
|
| 1046 |
-
keys.sort()
|
| 1047 |
-
for name in keys:
|
| 1048 |
-
value = locals[name]
|
| 1049 |
-
if name == "__builtins__":
|
| 1050 |
-
lines.append("__builtins__ = <builtins>")
|
| 1051 |
-
else:
|
| 1052 |
-
# This formatting could all be handled by the
|
| 1053 |
-
# _repr() function, which is only reprlib.Repr in
|
| 1054 |
-
# disguise, so is very configurable.
|
| 1055 |
-
if self.truncate_locals:
|
| 1056 |
-
str_repr = saferepr(value)
|
| 1057 |
-
else:
|
| 1058 |
-
str_repr = safeformat(value)
|
| 1059 |
-
# if len(str_repr) < 70 or not isinstance(value, (list, tuple, dict)):
|
| 1060 |
-
lines.append(f"{name:<10} = {str_repr}")
|
| 1061 |
-
# else:
|
| 1062 |
-
# self._line("%-10s =\\" % (name,))
|
| 1063 |
-
# # XXX
|
| 1064 |
-
# pprint.pprint(value, stream=self.excinfowriter)
|
| 1065 |
-
return ReprLocals(lines)
|
| 1066 |
-
return None
|
| 1067 |
-
|
| 1068 |
-
def repr_traceback_entry(
|
| 1069 |
-
self,
|
| 1070 |
-
entry: TracebackEntry | None,
|
| 1071 |
-
excinfo: ExceptionInfo[BaseException] | None = None,
|
| 1072 |
-
) -> ReprEntry:
|
| 1073 |
-
lines: list[str] = []
|
| 1074 |
-
style = (
|
| 1075 |
-
entry._repr_style
|
| 1076 |
-
if entry is not None and entry._repr_style is not None
|
| 1077 |
-
else self.style
|
| 1078 |
-
)
|
| 1079 |
-
if style in ("short", "long") and entry is not None:
|
| 1080 |
-
source = self._getentrysource(entry)
|
| 1081 |
-
if source is None:
|
| 1082 |
-
source = Source("???")
|
| 1083 |
-
line_index = 0
|
| 1084 |
-
end_line_index, colno, end_colno = None, None, None
|
| 1085 |
-
else:
|
| 1086 |
-
line_index = entry.relline
|
| 1087 |
-
end_line_index = entry.end_lineno_relative
|
| 1088 |
-
colno = entry.colno
|
| 1089 |
-
end_colno = entry.end_colno
|
| 1090 |
-
short = style == "short"
|
| 1091 |
-
reprargs = self.repr_args(entry) if not short else None
|
| 1092 |
-
s = self.get_source(
|
| 1093 |
-
source=source,
|
| 1094 |
-
line_index=line_index,
|
| 1095 |
-
excinfo=excinfo,
|
| 1096 |
-
short=short,
|
| 1097 |
-
end_line_index=end_line_index,
|
| 1098 |
-
colno=colno,
|
| 1099 |
-
end_colno=end_colno,
|
| 1100 |
-
)
|
| 1101 |
-
lines.extend(s)
|
| 1102 |
-
if short:
|
| 1103 |
-
message = f"in {entry.name}"
|
| 1104 |
-
else:
|
| 1105 |
-
message = (excinfo and excinfo.typename) or ""
|
| 1106 |
-
entry_path = entry.path
|
| 1107 |
-
path = self._makepath(entry_path)
|
| 1108 |
-
reprfileloc = ReprFileLocation(path, entry.lineno + 1, message)
|
| 1109 |
-
localsrepr = self.repr_locals(entry.locals)
|
| 1110 |
-
return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style)
|
| 1111 |
-
elif style == "value":
|
| 1112 |
-
if excinfo:
|
| 1113 |
-
lines.extend(str(excinfo.value).split("\n"))
|
| 1114 |
-
return ReprEntry(lines, None, None, None, style)
|
| 1115 |
-
else:
|
| 1116 |
-
if excinfo:
|
| 1117 |
-
lines.extend(self.get_exconly(excinfo, indent=4))
|
| 1118 |
-
return ReprEntry(lines, None, None, None, style)
|
| 1119 |
-
|
| 1120 |
-
def _makepath(self, path: Path | str) -> str:
|
| 1121 |
-
if not self.abspath and isinstance(path, Path):
|
| 1122 |
-
try:
|
| 1123 |
-
np = bestrelpath(Path.cwd(), path)
|
| 1124 |
-
except OSError:
|
| 1125 |
-
return str(path)
|
| 1126 |
-
if len(np) < len(str(path)):
|
| 1127 |
-
return np
|
| 1128 |
-
return str(path)
|
| 1129 |
-
|
| 1130 |
-
def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> ReprTraceback:
|
| 1131 |
-
traceback = filter_excinfo_traceback(self.tbfilter, excinfo)
|
| 1132 |
-
|
| 1133 |
-
if isinstance(excinfo.value, RecursionError):
|
| 1134 |
-
traceback, extraline = self._truncate_recursive_traceback(traceback)
|
| 1135 |
-
else:
|
| 1136 |
-
extraline = None
|
| 1137 |
-
|
| 1138 |
-
if not traceback:
|
| 1139 |
-
if extraline is None:
|
| 1140 |
-
extraline = "All traceback entries are hidden. Pass `--full-trace` to see hidden and internal frames."
|
| 1141 |
-
entries = [self.repr_traceback_entry(None, excinfo)]
|
| 1142 |
-
return ReprTraceback(entries, extraline, style=self.style)
|
| 1143 |
-
|
| 1144 |
-
last = traceback[-1]
|
| 1145 |
-
if self.style == "value":
|
| 1146 |
-
entries = [self.repr_traceback_entry(last, excinfo)]
|
| 1147 |
-
return ReprTraceback(entries, None, style=self.style)
|
| 1148 |
-
|
| 1149 |
-
entries = [
|
| 1150 |
-
self.repr_traceback_entry(entry, excinfo if last == entry else None)
|
| 1151 |
-
for entry in traceback
|
| 1152 |
-
]
|
| 1153 |
-
return ReprTraceback(entries, extraline, style=self.style)
|
| 1154 |
-
|
| 1155 |
-
def _truncate_recursive_traceback(
|
| 1156 |
-
self, traceback: Traceback
|
| 1157 |
-
) -> tuple[Traceback, str | None]:
|
| 1158 |
-
"""Truncate the given recursive traceback trying to find the starting
|
| 1159 |
-
point of the recursion.
|
| 1160 |
-
|
| 1161 |
-
The detection is done by going through each traceback entry and
|
| 1162 |
-
finding the point in which the locals of the frame are equal to the
|
| 1163 |
-
locals of a previous frame (see ``recursionindex()``).
|
| 1164 |
-
|
| 1165 |
-
Handle the situation where the recursion process might raise an
|
| 1166 |
-
exception (for example comparing numpy arrays using equality raises a
|
| 1167 |
-
TypeError), in which case we do our best to warn the user of the
|
| 1168 |
-
error and show a limited traceback.
|
| 1169 |
-
"""
|
| 1170 |
-
try:
|
| 1171 |
-
recursionindex = traceback.recursionindex()
|
| 1172 |
-
except Exception as e:
|
| 1173 |
-
max_frames = 10
|
| 1174 |
-
extraline: str | None = (
|
| 1175 |
-
"!!! Recursion error detected, but an error occurred locating the origin of recursion.\n"
|
| 1176 |
-
" The following exception happened when comparing locals in the stack frame:\n"
|
| 1177 |
-
f" {type(e).__name__}: {e!s}\n"
|
| 1178 |
-
f" Displaying first and last {max_frames} stack frames out of {len(traceback)}."
|
| 1179 |
-
)
|
| 1180 |
-
# Type ignored because adding two instances of a List subtype
|
| 1181 |
-
# currently incorrectly has type List instead of the subtype.
|
| 1182 |
-
traceback = traceback[:max_frames] + traceback[-max_frames:] # type: ignore
|
| 1183 |
-
else:
|
| 1184 |
-
if recursionindex is not None:
|
| 1185 |
-
extraline = "!!! Recursion detected (same locals & position)"
|
| 1186 |
-
traceback = traceback[: recursionindex + 1]
|
| 1187 |
-
else:
|
| 1188 |
-
extraline = None
|
| 1189 |
-
|
| 1190 |
-
return traceback, extraline
|
| 1191 |
-
|
| 1192 |
-
def repr_excinfo(self, excinfo: ExceptionInfo[BaseException]) -> ExceptionChainRepr:
|
| 1193 |
-
repr_chain: list[tuple[ReprTraceback, ReprFileLocation | None, str | None]] = []
|
| 1194 |
-
e: BaseException | None = excinfo.value
|
| 1195 |
-
excinfo_: ExceptionInfo[BaseException] | None = excinfo
|
| 1196 |
-
description = None
|
| 1197 |
-
seen: set[int] = set()
|
| 1198 |
-
while e is not None and id(e) not in seen:
|
| 1199 |
-
seen.add(id(e))
|
| 1200 |
-
|
| 1201 |
-
if excinfo_:
|
| 1202 |
-
# Fall back to native traceback as a temporary workaround until
|
| 1203 |
-
# full support for exception groups added to ExceptionInfo.
|
| 1204 |
-
# See https://github.com/pytest-dev/pytest/issues/9159
|
| 1205 |
-
reprtraceback: ReprTraceback | ReprTracebackNative
|
| 1206 |
-
if isinstance(e, BaseExceptionGroup):
|
| 1207 |
-
# don't filter any sub-exceptions since they shouldn't have any internal frames
|
| 1208 |
-
traceback = filter_excinfo_traceback(self.tbfilter, excinfo)
|
| 1209 |
-
extraline = (
|
| 1210 |
-
"All traceback entries are hidden. Pass `--full-trace` to see hidden and internal frames."
|
| 1211 |
-
if not traceback
|
| 1212 |
-
else None
|
| 1213 |
-
)
|
| 1214 |
-
reprtraceback = ReprTracebackNative(
|
| 1215 |
-
format_exception(
|
| 1216 |
-
type(excinfo.value),
|
| 1217 |
-
excinfo.value,
|
| 1218 |
-
traceback[0]._rawentry if traceback else None,
|
| 1219 |
-
),
|
| 1220 |
-
extraline=extraline,
|
| 1221 |
-
)
|
| 1222 |
-
|
| 1223 |
-
else:
|
| 1224 |
-
reprtraceback = self.repr_traceback(excinfo_)
|
| 1225 |
-
reprcrash = excinfo_._getreprcrash()
|
| 1226 |
-
else:
|
| 1227 |
-
# Fallback to native repr if the exception doesn't have a traceback:
|
| 1228 |
-
# ExceptionInfo objects require a full traceback to work.
|
| 1229 |
-
reprtraceback = ReprTracebackNative(format_exception(type(e), e, None))
|
| 1230 |
-
reprcrash = None
|
| 1231 |
-
repr_chain.append((reprtraceback, reprcrash, description))
|
| 1232 |
-
|
| 1233 |
-
if e.__cause__ is not None and self.chain:
|
| 1234 |
-
e = e.__cause__
|
| 1235 |
-
excinfo_ = ExceptionInfo.from_exception(e) if e.__traceback__ else None
|
| 1236 |
-
description = "The above exception was the direct cause of the following exception:"
|
| 1237 |
-
elif (
|
| 1238 |
-
e.__context__ is not None and not e.__suppress_context__ and self.chain
|
| 1239 |
-
):
|
| 1240 |
-
e = e.__context__
|
| 1241 |
-
excinfo_ = ExceptionInfo.from_exception(e) if e.__traceback__ else None
|
| 1242 |
-
description = "During handling of the above exception, another exception occurred:"
|
| 1243 |
-
else:
|
| 1244 |
-
e = None
|
| 1245 |
-
repr_chain.reverse()
|
| 1246 |
-
return ExceptionChainRepr(repr_chain)
|
| 1247 |
-
|
| 1248 |
-
|
| 1249 |
-
@dataclasses.dataclass(eq=False)
|
| 1250 |
-
class TerminalRepr:
|
| 1251 |
-
"""Base class for terminal representations -- pieces of data that display
|
| 1252 |
-
themselves to a terminal."""
|
| 1253 |
-
|
| 1254 |
-
def __str__(self) -> str:
|
| 1255 |
-
# FYI this is called from pytest-xdist's serialization of exception
|
| 1256 |
-
# information.
|
| 1257 |
-
io = StringIO()
|
| 1258 |
-
tw = TerminalWriter(file=io)
|
| 1259 |
-
self.toterminal(tw)
|
| 1260 |
-
return io.getvalue().strip()
|
| 1261 |
-
|
| 1262 |
-
def __repr__(self) -> str:
|
| 1263 |
-
return f"<{self.__class__} instance at {id(self):0x}>"
|
| 1264 |
-
|
| 1265 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1266 |
-
raise NotImplementedError()
|
| 1267 |
-
|
| 1268 |
-
|
| 1269 |
-
@dataclasses.dataclass(eq=False)
|
| 1270 |
-
class ExceptionRepr(TerminalRepr):
|
| 1271 |
-
"""Base class for exception terminal representations.
|
| 1272 |
-
|
| 1273 |
-
The representation generally contains:
|
| 1274 |
-
- The exception traceback (`reprtraceback`)
|
| 1275 |
-
- The exception message and location (`reprcrash`)
|
| 1276 |
-
- Separated, titled sections with additional data (pytest core doesn't use
|
| 1277 |
-
this currently).
|
| 1278 |
-
"""
|
| 1279 |
-
|
| 1280 |
-
reprtraceback: ReprTraceback
|
| 1281 |
-
reprcrash: ReprFileLocation | None
|
| 1282 |
-
sections: list[tuple[str, str, str]] = dataclasses.field(
|
| 1283 |
-
init=False, default_factory=list
|
| 1284 |
-
)
|
| 1285 |
-
|
| 1286 |
-
def addsection(self, name: str, content: str, sep: str = "-") -> None:
|
| 1287 |
-
self.sections.append((name, content, sep))
|
| 1288 |
-
|
| 1289 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1290 |
-
for name, content, sep in self.sections:
|
| 1291 |
-
tw.sep(sep, name)
|
| 1292 |
-
tw.line(content)
|
| 1293 |
-
|
| 1294 |
-
|
| 1295 |
-
@dataclasses.dataclass(eq=False)
|
| 1296 |
-
class ExceptionChainRepr(ExceptionRepr):
|
| 1297 |
-
"""A chain of exceptions, separated by descriptions (e.g. "The above
|
| 1298 |
-
exception was the direct cause of the following exception")."""
|
| 1299 |
-
|
| 1300 |
-
chain: Sequence[tuple[ReprTraceback, ReprFileLocation | None, str | None]]
|
| 1301 |
-
|
| 1302 |
-
def __init__(
|
| 1303 |
-
self,
|
| 1304 |
-
chain: Sequence[tuple[ReprTraceback, ReprFileLocation | None, str | None]],
|
| 1305 |
-
) -> None:
|
| 1306 |
-
# reprcrash and reprtraceback of the outermost (the newest) exception
|
| 1307 |
-
# in the chain.
|
| 1308 |
-
super().__init__(
|
| 1309 |
-
reprtraceback=chain[-1][0],
|
| 1310 |
-
reprcrash=chain[-1][1],
|
| 1311 |
-
)
|
| 1312 |
-
self.chain = chain
|
| 1313 |
-
|
| 1314 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1315 |
-
for reprtraceback, reprcrash, description in self.chain:
|
| 1316 |
-
reprtraceback.toterminal(tw)
|
| 1317 |
-
if description is not None:
|
| 1318 |
-
tw.line("")
|
| 1319 |
-
tw.line(description, yellow=True)
|
| 1320 |
-
super().toterminal(tw)
|
| 1321 |
-
|
| 1322 |
-
|
| 1323 |
-
@dataclasses.dataclass(eq=False)
|
| 1324 |
-
class ReprExceptionInfo(ExceptionRepr):
|
| 1325 |
-
"""A single exception with optional extra details (function arguments,
|
| 1326 |
-
function locals, file location) and possible extra line and sections emitted
|
| 1327 |
-
at the end."""
|
| 1328 |
-
|
| 1329 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1330 |
-
self.reprtraceback.toterminal(tw)
|
| 1331 |
-
super().toterminal(tw)
|
| 1332 |
-
|
| 1333 |
-
|
| 1334 |
-
@dataclasses.dataclass(eq=False)
|
| 1335 |
-
class ReprTraceback(TerminalRepr):
|
| 1336 |
-
"""A traceback with optional extra details (function arguments, function
|
| 1337 |
-
locals, file location) and possible extra line emitted at the end."""
|
| 1338 |
-
|
| 1339 |
-
reprentries: Sequence[ReprEntry | ReprEntryNative]
|
| 1340 |
-
extraline: str | None
|
| 1341 |
-
style: TracebackStyle
|
| 1342 |
-
|
| 1343 |
-
entrysep: ClassVar = "_ "
|
| 1344 |
-
|
| 1345 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1346 |
-
# The entries might have different styles.
|
| 1347 |
-
for i, entry in enumerate(self.reprentries):
|
| 1348 |
-
if entry.style == "long":
|
| 1349 |
-
tw.line("")
|
| 1350 |
-
entry.toterminal(tw)
|
| 1351 |
-
if i < len(self.reprentries) - 1:
|
| 1352 |
-
next_entry = self.reprentries[i + 1]
|
| 1353 |
-
if entry.style == "long" or (
|
| 1354 |
-
entry.style == "short" and next_entry.style == "long"
|
| 1355 |
-
):
|
| 1356 |
-
tw.sep(self.entrysep)
|
| 1357 |
-
|
| 1358 |
-
if self.extraline:
|
| 1359 |
-
tw.line(self.extraline)
|
| 1360 |
-
|
| 1361 |
-
|
| 1362 |
-
class ReprTracebackNative(ReprTraceback):
|
| 1363 |
-
"""A traceback in native style.
|
| 1364 |
-
|
| 1365 |
-
The lines are emitted as is; uses a single entry for the entire native
|
| 1366 |
-
traceback.
|
| 1367 |
-
"""
|
| 1368 |
-
|
| 1369 |
-
def __init__(self, tblines: Sequence[str], *, extraline: str | None = None) -> None:
|
| 1370 |
-
self.reprentries = [ReprEntryNative(tblines)]
|
| 1371 |
-
self.extraline = extraline
|
| 1372 |
-
self.style = "native"
|
| 1373 |
-
|
| 1374 |
-
|
| 1375 |
-
@dataclasses.dataclass(eq=False)
|
| 1376 |
-
class ReprEntryNative(TerminalRepr):
|
| 1377 |
-
"""An entry in a traceback in native style.
|
| 1378 |
-
|
| 1379 |
-
Emits the lines as is. The lines are assumed to include the line separators.
|
| 1380 |
-
|
| 1381 |
-
[Note that we currently use a single "entry" for the entire native
|
| 1382 |
-
traceback, so this is a bit misleading, but there's no point trying to parse
|
| 1383 |
-
or split a native traceback.]
|
| 1384 |
-
"""
|
| 1385 |
-
|
| 1386 |
-
lines: Sequence[str]
|
| 1387 |
-
|
| 1388 |
-
style: ClassVar[TracebackStyle] = "native"
|
| 1389 |
-
|
| 1390 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1391 |
-
tw.write("".join(self.lines))
|
| 1392 |
-
|
| 1393 |
-
|
| 1394 |
-
@dataclasses.dataclass(eq=False)
|
| 1395 |
-
class ReprEntry(TerminalRepr):
|
| 1396 |
-
"""An entry in a traceback with possible extra details (function arguments,
|
| 1397 |
-
function locals, source snippet, function's file and line)."""
|
| 1398 |
-
|
| 1399 |
-
lines: Sequence[str]
|
| 1400 |
-
reprfuncargs: ReprFuncArgs | None
|
| 1401 |
-
reprlocals: ReprLocals | None
|
| 1402 |
-
reprfileloc: ReprFileLocation | None
|
| 1403 |
-
style: TracebackStyle
|
| 1404 |
-
|
| 1405 |
-
def _write_entry_lines(self, tw: TerminalWriter) -> None:
|
| 1406 |
-
"""Write the source code portions of a list of traceback entries with syntax highlighting.
|
| 1407 |
-
|
| 1408 |
-
Usually entries are lines like these:
|
| 1409 |
-
|
| 1410 |
-
" x = 1"
|
| 1411 |
-
"> assert x == 2"
|
| 1412 |
-
"E assert 1 == 2"
|
| 1413 |
-
|
| 1414 |
-
This function takes care of rendering the "source" portions of it (the lines without
|
| 1415 |
-
the "E" prefix) using syntax highlighting, taking care to not highlighting the ">"
|
| 1416 |
-
character, as doing so might break line continuations.
|
| 1417 |
-
"""
|
| 1418 |
-
if not self.lines:
|
| 1419 |
-
return
|
| 1420 |
-
|
| 1421 |
-
if self.style == "value":
|
| 1422 |
-
# Using tw.write instead of tw.line for testing purposes due to TWMock implementation;
|
| 1423 |
-
# lines written with TWMock.line and TWMock._write_source cannot be distinguished
|
| 1424 |
-
# from each other, whereas lines written with TWMock.write are marked with TWMock.WRITE
|
| 1425 |
-
for line in self.lines:
|
| 1426 |
-
tw.write(line)
|
| 1427 |
-
tw.write("\n")
|
| 1428 |
-
return
|
| 1429 |
-
|
| 1430 |
-
# separate indents and source lines that are not failures: we want to
|
| 1431 |
-
# highlight the code but not the indentation, which may contain markers
|
| 1432 |
-
# such as "> assert 0"
|
| 1433 |
-
fail_marker = f"{ExceptionInfoFormatter.fail_marker} "
|
| 1434 |
-
indent_size = len(fail_marker)
|
| 1435 |
-
indents: list[str] = []
|
| 1436 |
-
source_lines: list[str] = []
|
| 1437 |
-
failure_lines: list[str] = []
|
| 1438 |
-
for index, line in enumerate(self.lines):
|
| 1439 |
-
is_failure_line = line.startswith(fail_marker)
|
| 1440 |
-
if is_failure_line:
|
| 1441 |
-
# from this point on all lines are considered part of the failure
|
| 1442 |
-
failure_lines.extend(self.lines[index:])
|
| 1443 |
-
break
|
| 1444 |
-
else:
|
| 1445 |
-
indents.append(line[:indent_size])
|
| 1446 |
-
source_lines.append(line[indent_size:])
|
| 1447 |
-
|
| 1448 |
-
tw._write_source(source_lines, indents)
|
| 1449 |
-
|
| 1450 |
-
# failure lines are always completely red and bold
|
| 1451 |
-
for line in failure_lines:
|
| 1452 |
-
tw.line(line, bold=True, red=True)
|
| 1453 |
-
|
| 1454 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1455 |
-
if self.style == "short":
|
| 1456 |
-
if self.reprfileloc:
|
| 1457 |
-
self.reprfileloc.toterminal(tw)
|
| 1458 |
-
self._write_entry_lines(tw)
|
| 1459 |
-
if self.reprlocals:
|
| 1460 |
-
self.reprlocals.toterminal(tw, indent=" " * 8)
|
| 1461 |
-
return
|
| 1462 |
-
|
| 1463 |
-
if self.reprfuncargs:
|
| 1464 |
-
self.reprfuncargs.toterminal(tw)
|
| 1465 |
-
|
| 1466 |
-
self._write_entry_lines(tw)
|
| 1467 |
-
|
| 1468 |
-
if self.reprlocals:
|
| 1469 |
-
tw.line("")
|
| 1470 |
-
self.reprlocals.toterminal(tw)
|
| 1471 |
-
if self.reprfileloc:
|
| 1472 |
-
if self.lines:
|
| 1473 |
-
tw.line("")
|
| 1474 |
-
self.reprfileloc.toterminal(tw)
|
| 1475 |
-
|
| 1476 |
-
def __str__(self) -> str:
|
| 1477 |
-
return "{}\n{}\n{}".format(
|
| 1478 |
-
"\n".join(self.lines), self.reprlocals, self.reprfileloc
|
| 1479 |
-
)
|
| 1480 |
-
|
| 1481 |
-
|
| 1482 |
-
@dataclasses.dataclass(eq=False)
|
| 1483 |
-
class ReprFileLocation(TerminalRepr):
|
| 1484 |
-
"""A message at a file location, using the `<path>:<lineno>: <message>`
|
| 1485 |
-
format that most editors understand.
|
| 1486 |
-
|
| 1487 |
-
Only the first line of the message is emitted.
|
| 1488 |
-
"""
|
| 1489 |
-
|
| 1490 |
-
path: str
|
| 1491 |
-
lineno: int
|
| 1492 |
-
message: str
|
| 1493 |
-
|
| 1494 |
-
def __post_init__(self) -> None:
|
| 1495 |
-
self.path = str(self.path)
|
| 1496 |
-
|
| 1497 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1498 |
-
msg = self.message
|
| 1499 |
-
i = msg.find("\n")
|
| 1500 |
-
if i != -1:
|
| 1501 |
-
msg = msg[:i]
|
| 1502 |
-
tw.write(self.path, bold=True, red=True)
|
| 1503 |
-
tw.line(f":{self.lineno}: {msg}")
|
| 1504 |
-
|
| 1505 |
-
|
| 1506 |
-
@dataclasses.dataclass(eq=False)
|
| 1507 |
-
class ReprLocals(TerminalRepr):
|
| 1508 |
-
"""Function local variables (pre-formatted)."""
|
| 1509 |
-
|
| 1510 |
-
lines: Sequence[str]
|
| 1511 |
-
|
| 1512 |
-
def toterminal(self, tw: TerminalWriter, indent: str = "") -> None:
|
| 1513 |
-
for line in self.lines:
|
| 1514 |
-
tw.line(indent + line)
|
| 1515 |
-
|
| 1516 |
-
|
| 1517 |
-
@dataclasses.dataclass(eq=False)
|
| 1518 |
-
class ReprFuncArgs(TerminalRepr):
|
| 1519 |
-
"""Function arguments - name = value, comma separated."""
|
| 1520 |
-
|
| 1521 |
-
args: Sequence[tuple[str, object]]
|
| 1522 |
-
|
| 1523 |
-
def toterminal(self, tw: TerminalWriter) -> None:
|
| 1524 |
-
if self.args:
|
| 1525 |
-
linesofar = ""
|
| 1526 |
-
for name, value in self.args:
|
| 1527 |
-
ns = f"{name} = {value}"
|
| 1528 |
-
if len(ns) + len(linesofar) + 2 > tw.fullwidth:
|
| 1529 |
-
if linesofar:
|
| 1530 |
-
tw.line(linesofar)
|
| 1531 |
-
linesofar = ns
|
| 1532 |
-
else:
|
| 1533 |
-
if linesofar:
|
| 1534 |
-
linesofar += ", " + ns
|
| 1535 |
-
else:
|
| 1536 |
-
linesofar = ns
|
| 1537 |
-
if linesofar:
|
| 1538 |
-
tw.line(linesofar)
|
| 1539 |
-
tw.line("")
|
| 1540 |
-
|
| 1541 |
-
|
| 1542 |
-
def getfslineno(obj: object) -> tuple[str | Path, int]:
|
| 1543 |
-
"""Return source location (path, lineno) for the given object.
|
| 1544 |
-
|
| 1545 |
-
If the source cannot be determined return ("", -1).
|
| 1546 |
-
|
| 1547 |
-
The line number is 0-based.
|
| 1548 |
-
"""
|
| 1549 |
-
# xxx let decorators etc specify a sane ordering
|
| 1550 |
-
# NOTE: this used to be done in _pytest.compat.getfslineno, initially added
|
| 1551 |
-
# in 6ec13a2b9. It ("place_as") appears to be something very custom.
|
| 1552 |
-
obj = get_real_func(obj)
|
| 1553 |
-
if hasattr(obj, "place_as"):
|
| 1554 |
-
obj = obj.place_as
|
| 1555 |
-
|
| 1556 |
-
try:
|
| 1557 |
-
code = Code.from_function(obj)
|
| 1558 |
-
except TypeError:
|
| 1559 |
-
try:
|
| 1560 |
-
fn = inspect.getsourcefile(obj) or inspect.getfile(obj) # type: ignore[arg-type]
|
| 1561 |
-
except TypeError:
|
| 1562 |
-
return "", -1
|
| 1563 |
-
|
| 1564 |
-
fspath = (fn and absolutepath(fn)) or ""
|
| 1565 |
-
lineno = -1
|
| 1566 |
-
if fspath:
|
| 1567 |
-
try:
|
| 1568 |
-
_, lineno = findsource(obj)
|
| 1569 |
-
except OSError:
|
| 1570 |
-
pass
|
| 1571 |
-
return fspath, lineno
|
| 1572 |
-
|
| 1573 |
-
return code.path, code.firstlineno
|
| 1574 |
-
|
| 1575 |
-
|
| 1576 |
-
def _byte_offset_to_character_offset(str, offset):
|
| 1577 |
-
"""Converts a byte based offset in a string to a code-point."""
|
| 1578 |
-
as_utf8 = str.encode("utf-8")
|
| 1579 |
-
return len(as_utf8[:offset].decode("utf-8", errors="replace"))
|
| 1580 |
-
|
| 1581 |
-
|
| 1582 |
-
# Relative paths that we use to filter traceback entries from appearing to the user;
|
| 1583 |
-
# see filter_traceback.
|
| 1584 |
-
# note: if we need to add more paths than what we have now we should probably use a list
|
| 1585 |
-
# for better maintenance.
|
| 1586 |
-
|
| 1587 |
-
_PLUGGY_DIR = Path(pluggy.__file__.rstrip("oc"))
|
| 1588 |
-
# pluggy is either a package or a single module depending on the version
|
| 1589 |
-
if _PLUGGY_DIR.name == "__init__.py":
|
| 1590 |
-
_PLUGGY_DIR = _PLUGGY_DIR.parent
|
| 1591 |
-
_PYTEST_DIR = Path(_pytest.__file__).parent
|
| 1592 |
-
|
| 1593 |
-
|
| 1594 |
-
def filter_traceback(entry: TracebackEntry) -> bool:
|
| 1595 |
-
"""Return True if a TracebackEntry instance should be included in tracebacks.
|
| 1596 |
-
|
| 1597 |
-
We hide traceback entries of:
|
| 1598 |
-
|
| 1599 |
-
* dynamically generated code (no code to show up for it);
|
| 1600 |
-
* internal traceback from pytest or its internal libraries, py and pluggy.
|
| 1601 |
-
"""
|
| 1602 |
-
# entry.path might sometimes return a str object when the entry
|
| 1603 |
-
# points to dynamically generated code.
|
| 1604 |
-
# See https://bitbucket.org/pytest-dev/py/issues/71.
|
| 1605 |
-
raw_filename = entry.frame.code.raw.co_filename
|
| 1606 |
-
is_generated = "<" in raw_filename and ">" in raw_filename
|
| 1607 |
-
if is_generated:
|
| 1608 |
-
return False
|
| 1609 |
-
|
| 1610 |
-
# entry.path might point to a non-existing file, in which case it will
|
| 1611 |
-
# also return a str object. See #1133.
|
| 1612 |
-
p = Path(entry.path)
|
| 1613 |
-
|
| 1614 |
-
parents = p.parents
|
| 1615 |
-
if _PLUGGY_DIR in parents:
|
| 1616 |
-
return False
|
| 1617 |
-
if _PYTEST_DIR in parents:
|
| 1618 |
-
return False
|
| 1619 |
-
|
| 1620 |
-
return True
|
| 1621 |
-
|
| 1622 |
-
|
| 1623 |
-
def filter_excinfo_traceback(
|
| 1624 |
-
tbfilter: TracebackFilter, excinfo: ExceptionInfo[BaseException]
|
| 1625 |
-
) -> Traceback:
|
| 1626 |
-
"""Filter the exception traceback in ``excinfo`` according to ``tbfilter``."""
|
| 1627 |
-
if callable(tbfilter):
|
| 1628 |
-
return tbfilter(excinfo)
|
| 1629 |
-
elif tbfilter:
|
| 1630 |
-
return excinfo.traceback.filter(excinfo)
|
| 1631 |
-
else:
|
| 1632 |
-
return excinfo.traceback
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_pytest/_code/source.py
DELETED
|
@@ -1,228 +0,0 @@
|
|
| 1 |
-
# mypy: allow-untyped-defs
|
| 2 |
-
from __future__ import annotations
|
| 3 |
-
|
| 4 |
-
import ast
|
| 5 |
-
from bisect import bisect_right
|
| 6 |
-
from collections.abc import Iterable
|
| 7 |
-
from collections.abc import Iterator
|
| 8 |
-
import inspect
|
| 9 |
-
import textwrap
|
| 10 |
-
import tokenize
|
| 11 |
-
import types
|
| 12 |
-
from typing import overload
|
| 13 |
-
import warnings
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
class Source:
|
| 17 |
-
"""An immutable object holding a source code fragment.
|
| 18 |
-
|
| 19 |
-
When using Source(...), the source lines are deindented.
|
| 20 |
-
"""
|
| 21 |
-
|
| 22 |
-
def __init__(self, obj: object = None) -> None:
|
| 23 |
-
if not obj:
|
| 24 |
-
self.lines: list[str] = []
|
| 25 |
-
self.raw_lines: list[str] = []
|
| 26 |
-
elif isinstance(obj, Source):
|
| 27 |
-
self.lines = obj.lines
|
| 28 |
-
self.raw_lines = obj.raw_lines
|
| 29 |
-
elif isinstance(obj, tuple | list):
|
| 30 |
-
self.lines = deindent(x.rstrip("\n") for x in obj)
|
| 31 |
-
self.raw_lines = list(x.rstrip("\n") for x in obj)
|
| 32 |
-
elif isinstance(obj, str):
|
| 33 |
-
self.lines = deindent(obj.split("\n"))
|
| 34 |
-
self.raw_lines = obj.split("\n")
|
| 35 |
-
else:
|
| 36 |
-
try:
|
| 37 |
-
rawcode = getrawcode(obj)
|
| 38 |
-
src = inspect.getsource(rawcode)
|
| 39 |
-
except TypeError:
|
| 40 |
-
src = inspect.getsource(obj) # type: ignore[arg-type]
|
| 41 |
-
self.lines = deindent(src.split("\n"))
|
| 42 |
-
self.raw_lines = src.split("\n")
|
| 43 |
-
|
| 44 |
-
def __eq__(self, other: object) -> bool:
|
| 45 |
-
if not isinstance(other, Source):
|
| 46 |
-
return NotImplemented
|
| 47 |
-
return self.lines == other.lines
|
| 48 |
-
|
| 49 |
-
# Ignore type because of https://github.com/python/mypy/issues/4266.
|
| 50 |
-
__hash__ = None # type: ignore
|
| 51 |
-
|
| 52 |
-
@overload
|
| 53 |
-
def __getitem__(self, key: int) -> str: ...
|
| 54 |
-
|
| 55 |
-
@overload
|
| 56 |
-
def __getitem__(self, key: slice) -> Source: ...
|
| 57 |
-
|
| 58 |
-
def __getitem__(self, key: int | slice) -> str | Source:
|
| 59 |
-
if isinstance(key, int):
|
| 60 |
-
return self.lines[key]
|
| 61 |
-
else:
|
| 62 |
-
if key.step not in (None, 1):
|
| 63 |
-
raise IndexError("cannot slice a Source with a step")
|
| 64 |
-
newsource = Source()
|
| 65 |
-
newsource.lines = self.lines[key.start : key.stop]
|
| 66 |
-
newsource.raw_lines = self.raw_lines[key.start : key.stop]
|
| 67 |
-
return newsource
|
| 68 |
-
|
| 69 |
-
def __iter__(self) -> Iterator[str]:
|
| 70 |
-
return iter(self.lines)
|
| 71 |
-
|
| 72 |
-
def __len__(self) -> int:
|
| 73 |
-
return len(self.lines)
|
| 74 |
-
|
| 75 |
-
def strip(self) -> Source:
|
| 76 |
-
"""Return new Source object with trailing and leading blank lines removed."""
|
| 77 |
-
start, end = 0, len(self)
|
| 78 |
-
while start < end and not self.lines[start].strip():
|
| 79 |
-
start += 1
|
| 80 |
-
while end > start and not self.lines[end - 1].strip():
|
| 81 |
-
end -= 1
|
| 82 |
-
source = Source()
|
| 83 |
-
source.raw_lines = self.raw_lines
|
| 84 |
-
source.lines[:] = self.lines[start:end]
|
| 85 |
-
return source
|
| 86 |
-
|
| 87 |
-
def indent(self, indent: str = " " * 4) -> Source:
|
| 88 |
-
"""Return a copy of the source object with all lines indented by the
|
| 89 |
-
given indent-string."""
|
| 90 |
-
newsource = Source()
|
| 91 |
-
newsource.raw_lines = self.raw_lines
|
| 92 |
-
newsource.lines = [(indent + line) for line in self.lines]
|
| 93 |
-
return newsource
|
| 94 |
-
|
| 95 |
-
def getstatement(self, lineno: int) -> Source:
|
| 96 |
-
"""Return Source statement which contains the given linenumber
|
| 97 |
-
(counted from 0)."""
|
| 98 |
-
start, end = self.getstatementrange(lineno)
|
| 99 |
-
return self[start:end]
|
| 100 |
-
|
| 101 |
-
def getstatementrange(self, lineno: int) -> tuple[int, int]:
|
| 102 |
-
"""Return (start, end) tuple which spans the minimal statement region
|
| 103 |
-
which containing the given lineno."""
|
| 104 |
-
if not (0 <= lineno < len(self)):
|
| 105 |
-
raise IndexError("lineno out of range")
|
| 106 |
-
_ast, start, end = getstatementrange_ast(lineno, self)
|
| 107 |
-
return start, end
|
| 108 |
-
|
| 109 |
-
def deindent(self) -> Source:
|
| 110 |
-
"""Return a new Source object deindented."""
|
| 111 |
-
newsource = Source()
|
| 112 |
-
newsource.lines[:] = deindent(self.lines)
|
| 113 |
-
newsource.raw_lines = self.raw_lines
|
| 114 |
-
return newsource
|
| 115 |
-
|
| 116 |
-
def __str__(self) -> str:
|
| 117 |
-
return "\n".join(self.lines)
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
#
|
| 121 |
-
# helper functions
|
| 122 |
-
#
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
def findsource(obj) -> tuple[Source | None, int]:
|
| 126 |
-
try:
|
| 127 |
-
sourcelines, lineno = inspect.findsource(obj)
|
| 128 |
-
except Exception:
|
| 129 |
-
return None, -1
|
| 130 |
-
source = Source()
|
| 131 |
-
source.lines = [line.rstrip() for line in sourcelines]
|
| 132 |
-
source.raw_lines = sourcelines
|
| 133 |
-
return source, lineno
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
def getrawcode(obj: object, trycall: bool = True) -> types.CodeType:
|
| 137 |
-
"""Return code object for given function."""
|
| 138 |
-
try:
|
| 139 |
-
return obj.__code__ # type: ignore[attr-defined,no-any-return]
|
| 140 |
-
except AttributeError:
|
| 141 |
-
pass
|
| 142 |
-
if trycall:
|
| 143 |
-
call = getattr(obj, "__call__", None)
|
| 144 |
-
if call and not isinstance(obj, type):
|
| 145 |
-
return getrawcode(call, trycall=False)
|
| 146 |
-
raise TypeError(f"could not get code object for {obj!r}")
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
def deindent(lines: Iterable[str]) -> list[str]:
|
| 150 |
-
return textwrap.dedent("\n".join(lines)).splitlines()
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
def get_statement_startend2(lineno: int, node: ast.AST) -> tuple[int, int | None]:
|
| 154 |
-
# Flatten all statements and except handlers into one lineno-list.
|
| 155 |
-
# AST's line numbers start indexing at 1.
|
| 156 |
-
values: list[int] = []
|
| 157 |
-
for x in ast.walk(node):
|
| 158 |
-
if isinstance(x, ast.stmt | ast.ExceptHandler):
|
| 159 |
-
# The lineno points to the class/def, so need to include the decorators.
|
| 160 |
-
if isinstance(x, ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef):
|
| 161 |
-
for d in x.decorator_list:
|
| 162 |
-
values.append(d.lineno - 1)
|
| 163 |
-
values.append(x.lineno - 1)
|
| 164 |
-
for name in ("finalbody", "orelse"):
|
| 165 |
-
val: list[ast.stmt] | None = getattr(x, name, None)
|
| 166 |
-
if val:
|
| 167 |
-
# Treat the finally/orelse part as its own statement.
|
| 168 |
-
values.append(val[0].lineno - 1 - 1)
|
| 169 |
-
values.sort()
|
| 170 |
-
insert_index = bisect_right(values, lineno)
|
| 171 |
-
if insert_index == 0:
|
| 172 |
-
return 0, None
|
| 173 |
-
start = values[insert_index - 1]
|
| 174 |
-
if insert_index >= len(values):
|
| 175 |
-
end = None
|
| 176 |
-
else:
|
| 177 |
-
end = values[insert_index]
|
| 178 |
-
return start, end
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
def getstatementrange_ast(
|
| 182 |
-
lineno: int,
|
| 183 |
-
source: Source,
|
| 184 |
-
assertion: bool = False,
|
| 185 |
-
astnode: ast.AST | None = None,
|
| 186 |
-
) -> tuple[ast.AST, int, int]:
|
| 187 |
-
if astnode is None:
|
| 188 |
-
content = str(source)
|
| 189 |
-
# See #4260:
|
| 190 |
-
# Don't produce duplicate warnings when compiling source to find AST.
|
| 191 |
-
with warnings.catch_warnings():
|
| 192 |
-
warnings.simplefilter("ignore")
|
| 193 |
-
astnode = ast.parse(content, "source", "exec")
|
| 194 |
-
|
| 195 |
-
start, end = get_statement_startend2(lineno, astnode)
|
| 196 |
-
# We need to correct the end:
|
| 197 |
-
# - ast-parsing strips comments
|
| 198 |
-
# - there might be empty lines
|
| 199 |
-
# - we might have lesser indented code blocks at the end
|
| 200 |
-
if end is None:
|
| 201 |
-
end = len(source.lines)
|
| 202 |
-
|
| 203 |
-
if end > start + 1:
|
| 204 |
-
# Make sure we don't span differently indented code blocks
|
| 205 |
-
# by using the BlockFinder helper used which inspect.getsource() uses itself.
|
| 206 |
-
block_finder = inspect.BlockFinder()
|
| 207 |
-
# If we start with an indented line, put blockfinder to "started" mode.
|
| 208 |
-
block_finder.started = (
|
| 209 |
-
bool(source.lines[start]) and source.lines[start][0].isspace()
|
| 210 |
-
)
|
| 211 |
-
it = ((x + "\n") for x in source.lines[start:end])
|
| 212 |
-
try:
|
| 213 |
-
for tok in tokenize.generate_tokens(lambda: next(it)):
|
| 214 |
-
block_finder.tokeneater(*tok)
|
| 215 |
-
except (inspect.EndOfBlock, IndentationError):
|
| 216 |
-
end = block_finder.last + start
|
| 217 |
-
except Exception:
|
| 218 |
-
pass
|
| 219 |
-
|
| 220 |
-
# The end might still point to a comment or empty line, correct it.
|
| 221 |
-
end = min(end, len(source.lines))
|
| 222 |
-
while end:
|
| 223 |
-
line = source.lines[end - 1].lstrip()
|
| 224 |
-
if line.startswith("#") or not line:
|
| 225 |
-
end -= 1
|
| 226 |
-
else:
|
| 227 |
-
break
|
| 228 |
-
return astnode, start, end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_pytest/_io/__init__.py
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
from .terminalwriter import get_terminal_width
|
| 4 |
-
from .terminalwriter import TerminalWriter
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
__all__ = [
|
| 8 |
-
"TerminalWriter",
|
| 9 |
-
"get_terminal_width",
|
| 10 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.venv/lib/python3.12/site-packages/_pytest/_io/pprint.py
DELETED
|
@@ -1,673 +0,0 @@
|
|
| 1 |
-
# mypy: allow-untyped-defs
|
| 2 |
-
# This module was imported from the cpython standard library
|
| 3 |
-
# (https://github.com/python/cpython/) at commit
|
| 4 |
-
# c5140945c723ae6c4b7ee81ff720ac8ea4b52cfd (python3.12).
|
| 5 |
-
#
|
| 6 |
-
#
|
| 7 |
-
# Original Author: Fred L. Drake, Jr.
|
| 8 |
-
# fdrake@acm.org
|
| 9 |
-
#
|
| 10 |
-
# This is a simple little module I wrote to make life easier. I didn't
|
| 11 |
-
# see anything quite like it in the library, though I may have overlooked
|
| 12 |
-
# something. I wrote this when I was trying to read some heavily nested
|
| 13 |
-
# tuples with fairly non-descriptive content. This is modeled very much
|
| 14 |
-
# after Lisp/Scheme - style pretty-printing of lists. If you find it
|
| 15 |
-
# useful, thank small children who sleep at night.
|
| 16 |
-
from __future__ import annotations
|
| 17 |
-
|
| 18 |
-
import collections as _collections
|
| 19 |
-
from collections.abc import Callable
|
| 20 |
-
from collections.abc import Iterator
|
| 21 |
-
import dataclasses as _dataclasses
|
| 22 |
-
from io import StringIO as _StringIO
|
| 23 |
-
import re
|
| 24 |
-
import types as _types
|
| 25 |
-
from typing import Any
|
| 26 |
-
from typing import IO
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
class _safe_key:
|
| 30 |
-
"""Helper function for key functions when sorting unorderable objects.
|
| 31 |
-
|
| 32 |
-
The wrapped-object will fallback to a Py2.x style comparison for
|
| 33 |
-
unorderable types (sorting first comparing the type name and then by
|
| 34 |
-
the obj ids). Does not work recursively, so dict.items() must have
|
| 35 |
-
_safe_key applied to both the key and the value.
|
| 36 |
-
|
| 37 |
-
"""
|
| 38 |
-
|
| 39 |
-
__slots__ = ["obj"]
|
| 40 |
-
|
| 41 |
-
def __init__(self, obj):
|
| 42 |
-
self.obj = obj
|
| 43 |
-
|
| 44 |
-
def __lt__(self, other):
|
| 45 |
-
try:
|
| 46 |
-
return self.obj < other.obj
|
| 47 |
-
except TypeError:
|
| 48 |
-
return (str(type(self.obj)), id(self.obj)) < (
|
| 49 |
-
str(type(other.obj)),
|
| 50 |
-
id(other.obj),
|
| 51 |
-
)
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
def _safe_tuple(t):
|
| 55 |
-
"""Helper function for comparing 2-tuples"""
|
| 56 |
-
return _safe_key(t[0]), _safe_key(t[1])
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
class PrettyPrinter:
|
| 60 |
-
def __init__(
|
| 61 |
-
self,
|
| 62 |
-
indent: int = 4,
|
| 63 |
-
width: int = 80,
|
| 64 |
-
depth: int | None = None,
|
| 65 |
-
) -> None:
|
| 66 |
-
"""Handle pretty printing operations onto a stream using a set of
|
| 67 |
-
configured parameters.
|
| 68 |
-
|
| 69 |
-
indent
|
| 70 |
-
Number of spaces to indent for each level of nesting.
|
| 71 |
-
|
| 72 |
-
width
|
| 73 |
-
Attempted maximum number of columns in the output.
|
| 74 |
-
|
| 75 |
-
depth
|
| 76 |
-
The maximum depth to print out nested structures.
|
| 77 |
-
|
| 78 |
-
"""
|
| 79 |
-
if indent < 0:
|
| 80 |
-
raise ValueError("indent must be >= 0")
|
| 81 |
-
if depth is not None and depth <= 0:
|
| 82 |
-
raise ValueError("depth must be > 0")
|
| 83 |
-
if not width:
|
| 84 |
-
raise ValueError("width must be != 0")
|
| 85 |
-
self._depth = depth
|
| 86 |
-
self._indent_per_level = indent
|
| 87 |
-
self._width = width
|
| 88 |
-
|
| 89 |
-
def pformat(self, object: Any) -> str:
|
| 90 |
-
sio = _StringIO()
|
| 91 |
-
self._format(object, sio, 0, 0, set(), 0)
|
| 92 |
-
return sio.getvalue()
|
| 93 |
-
|
| 94 |
-
def _format(
|
| 95 |
-
self,
|
| 96 |
-
object: Any,
|
| 97 |
-
stream: IO[str],
|
| 98 |
-
indent: int,
|
| 99 |
-
allowance: int,
|
| 100 |
-
context: set[int],
|
| 101 |
-
level: int,
|
| 102 |
-
) -> None:
|
| 103 |
-
objid = id(object)
|
| 104 |
-
if objid in context:
|
| 105 |
-
stream.write(_recursion(object))
|
| 106 |
-
return
|
| 107 |
-
|
| 108 |
-
p = self._dispatch.get(type(object).__repr__, None)
|
| 109 |
-
if p is not None:
|
| 110 |
-
context.add(objid)
|
| 111 |
-
p(self, object, stream, indent, allowance, context, level + 1)
|
| 112 |
-
context.remove(objid)
|
| 113 |
-
elif (
|
| 114 |
-
_dataclasses.is_dataclass(object)
|
| 115 |
-
and not isinstance(object, type)
|
| 116 |
-
and object.__dataclass_params__.repr # type:ignore[attr-defined]
|
| 117 |
-
and
|
| 118 |
-
# Check dataclass has generated repr method.
|
| 119 |
-
hasattr(object.__repr__, "__wrapped__")
|
| 120 |
-
and "__create_fn__" in object.__repr__.__wrapped__.__qualname__
|
| 121 |
-
):
|
| 122 |
-
context.add(objid)
|
| 123 |
-
self._pprint_dataclass(
|
| 124 |
-
object, stream, indent, allowance, context, level + 1
|
| 125 |
-
)
|
| 126 |
-
context.remove(objid)
|
| 127 |
-
else:
|
| 128 |
-
stream.write(self._repr(object, context, level))
|
| 129 |
-
|
| 130 |
-
def _pprint_dataclass(
|
| 131 |
-
self,
|
| 132 |
-
object: Any,
|
| 133 |
-
stream: IO[str],
|
| 134 |
-
indent: int,
|
| 135 |
-
allowance: int,
|
| 136 |
-
context: set[int],
|
| 137 |
-
level: int,
|
| 138 |
-
) -> None:
|
| 139 |
-
cls_name = object.__class__.__name__
|
| 140 |
-
items = [
|
| 141 |
-
(f.name, getattr(object, f.name))
|
| 142 |
-
for f in _dataclasses.fields(object)
|
| 143 |
-
if f.repr
|
| 144 |
-
]
|
| 145 |
-
stream.write(cls_name + "(")
|
| 146 |
-
self._format_namespace_items(items, stream, indent, allowance, context, level)
|
| 147 |
-
stream.write(")")
|
| 148 |
-
|
| 149 |
-
_dispatch: dict[
|
| 150 |
-
Callable[..., str],
|
| 151 |
-
Callable[[PrettyPrinter, Any, IO[str], int, int, set[int], int], None],
|
| 152 |
-
] = {}
|
| 153 |
-
|
| 154 |
-
def _pprint_dict(
|
| 155 |
-
self,
|
| 156 |
-
object: Any,
|
| 157 |
-
stream: IO[str],
|
| 158 |
-
indent: int,
|
| 159 |
-
allowance: int,
|
| 160 |
-
context: set[int],
|
| 161 |
-
level: int,
|
| 162 |
-
) -> None:
|
| 163 |
-
write = stream.write
|
| 164 |
-
write("{")
|
| 165 |
-
items = object.items()
|
| 166 |
-
self._format_dict_items(items, stream, indent, allowance, context, level)
|
| 167 |
-
write("}")
|
| 168 |
-
|
| 169 |
-
_dispatch[dict.__repr__] = _pprint_dict
|
| 170 |
-
|
| 171 |
-
def _pprint_ordered_dict(
|
| 172 |
-
self,
|
| 173 |
-
object: Any,
|
| 174 |
-
stream: IO[str],
|
| 175 |
-
indent: int,
|
| 176 |
-
allowance: int,
|
| 177 |
-
context: set[int],
|
| 178 |
-
level: int,
|
| 179 |
-
) -> None:
|
| 180 |
-
if not len(object):
|
| 181 |
-
stream.write(repr(object))
|
| 182 |
-
return
|
| 183 |
-
cls = object.__class__
|
| 184 |
-
stream.write(cls.__name__ + "(")
|
| 185 |
-
self._pprint_dict(object, stream, indent, allowance, context, level)
|
| 186 |
-
stream.write(")")
|
| 187 |
-
|
| 188 |
-
_dispatch[_collections.OrderedDict.__repr__] = _pprint_ordered_dict
|
| 189 |
-
|
| 190 |
-
def _pprint_list(
|
| 191 |
-
self,
|
| 192 |
-
object: Any,
|
| 193 |
-
stream: IO[str],
|
| 194 |
-
indent: int,
|
| 195 |
-
allowance: int,
|
| 196 |
-
context: set[int],
|
| 197 |
-
level: int,
|
| 198 |
-
) -> None:
|
| 199 |
-
stream.write("[")
|
| 200 |
-
self._format_items(object, stream, indent, allowance, context, level)
|
| 201 |
-
stream.write("]")
|
| 202 |
-
|
| 203 |
-
_dispatch[list.__repr__] = _pprint_list
|
| 204 |
-
|
| 205 |
-
def _pprint_tuple(
|
| 206 |
-
self,
|
| 207 |
-
object: Any,
|
| 208 |
-
stream: IO[str],
|
| 209 |
-
indent: int,
|
| 210 |
-
allowance: int,
|
| 211 |
-
context: set[int],
|
| 212 |
-
level: int,
|
| 213 |
-
) -> None:
|
| 214 |
-
stream.write("(")
|
| 215 |
-
self._format_items(object, stream, indent, allowance, context, level)
|
| 216 |
-
stream.write(")")
|
| 217 |
-
|
| 218 |
-
_dispatch[tuple.__repr__] = _pprint_tuple
|
| 219 |
-
|
| 220 |
-
def _pprint_set(
|
| 221 |
-
self,
|
| 222 |
-
object: Any,
|
| 223 |
-
stream: IO[str],
|
| 224 |
-
indent: int,
|
| 225 |
-
allowance: int,
|
| 226 |
-
context: set[int],
|
| 227 |
-
level: int,
|
| 228 |
-
) -> None:
|
| 229 |
-
if not len(object):
|
| 230 |
-
stream.write(repr(object))
|
| 231 |
-
return
|
| 232 |
-
typ = object.__class__
|
| 233 |
-
if typ is set:
|
| 234 |
-
stream.write("{")
|
| 235 |
-
endchar = "}"
|
| 236 |
-
else:
|
| 237 |
-
stream.write(typ.__name__ + "({")
|
| 238 |
-
endchar = "})"
|
| 239 |
-
object = sorted(object, key=_safe_key)
|
| 240 |
-
self._format_items(object, stream, indent, allowance, context, level)
|
| 241 |
-
stream.write(endchar)
|
| 242 |
-
|
| 243 |
-
_dispatch[set.__repr__] = _pprint_set
|
| 244 |
-
_dispatch[frozenset.__repr__] = _pprint_set
|
| 245 |
-
|
| 246 |
-
def _pprint_str(
|
| 247 |
-
self,
|
| 248 |
-
object: Any,
|
| 249 |
-
stream: IO[str],
|
| 250 |
-
indent: int,
|
| 251 |
-
allowance: int,
|
| 252 |
-
context: set[int],
|
| 253 |
-
level: int,
|
| 254 |
-
) -> None:
|
| 255 |
-
write = stream.write
|
| 256 |
-
if not len(object):
|
| 257 |
-
write(repr(object))
|
| 258 |
-
return
|
| 259 |
-
chunks = []
|
| 260 |
-
lines = object.splitlines(True)
|
| 261 |
-
if level == 1:
|
| 262 |
-
indent += 1
|
| 263 |
-
allowance += 1
|
| 264 |
-
max_width1 = max_width = self._width - indent
|
| 265 |
-
for i, line in enumerate(lines):
|
| 266 |
-
rep = repr(line)
|
| 267 |
-
if i == len(lines) - 1:
|
| 268 |
-
max_width1 -= allowance
|
| 269 |
-
if len(rep) <= max_width1:
|
| 270 |
-
chunks.append(rep)
|
| 271 |
-
else:
|
| 272 |
-
# A list of alternating (non-space, space) strings
|
| 273 |
-
parts = re.findall(r"\S*\s*", line)
|
| 274 |
-
assert parts
|
| 275 |
-
assert not parts[-1]
|
| 276 |
-
parts.pop() # drop empty last part
|
| 277 |
-
max_width2 = max_width
|
| 278 |
-
current = ""
|
| 279 |
-
for j, part in enumerate(parts):
|
| 280 |
-
candidate = current + part
|
| 281 |
-
if j == len(parts) - 1 and i == len(lines) - 1:
|
| 282 |
-
max_width2 -= allowance
|
| 283 |
-
if len(repr(candidate)) > max_width2:
|
| 284 |
-
if current:
|
| 285 |
-
chunks.append(repr(current))
|
| 286 |
-
current = part
|
| 287 |
-
else:
|
| 288 |
-
current = candidate
|
| 289 |
-
if current:
|
| 290 |
-
chunks.append(repr(current))
|
| 291 |
-
if len(chunks) == 1:
|
| 292 |
-
write(rep)
|
| 293 |
-
return
|
| 294 |
-
if level == 1:
|
| 295 |
-
write("(")
|
| 296 |
-
for i, rep in enumerate(chunks):
|
| 297 |
-
if i > 0:
|
| 298 |
-
write("\n" + " " * indent)
|
| 299 |
-
write(rep)
|
| 300 |
-
if level == 1:
|
| 301 |
-
write(")")
|
| 302 |
-
|
| 303 |
-
_dispatch[str.__repr__] = _pprint_str
|
| 304 |
-
|
| 305 |
-
def _pprint_bytes(
|
| 306 |
-
self,
|
| 307 |
-
object: Any,
|
| 308 |
-
stream: IO[str],
|
| 309 |
-
indent: int,
|
| 310 |
-
allowance: int,
|
| 311 |
-
context: set[int],
|
| 312 |
-
level: int,
|
| 313 |
-
) -> None:
|
| 314 |
-
write = stream.write
|
| 315 |
-
if len(object) <= 4:
|
| 316 |
-
write(repr(object))
|
| 317 |
-
return
|
| 318 |
-
parens = level == 1
|
| 319 |
-
if parens:
|
| 320 |
-
indent += 1
|
| 321 |
-
allowance += 1
|
| 322 |
-
write("(")
|
| 323 |
-
delim = ""
|
| 324 |
-
for rep in _wrap_bytes_repr(object, self._width - indent, allowance):
|
| 325 |
-
write(delim)
|
| 326 |
-
write(rep)
|
| 327 |
-
if not delim:
|
| 328 |
-
delim = "\n" + " " * indent
|
| 329 |
-
if parens:
|
| 330 |
-
write(")")
|
| 331 |
-
|
| 332 |
-
_dispatch[bytes.__repr__] = _pprint_bytes
|
| 333 |
-
|
| 334 |
-
def _pprint_bytearray(
|
| 335 |
-
self,
|
| 336 |
-
object: Any,
|
| 337 |
-
stream: IO[str],
|
| 338 |
-
indent: int,
|
| 339 |
-
allowance: int,
|
| 340 |
-
context: set[int],
|
| 341 |
-
level: int,
|
| 342 |
-
) -> None:
|
| 343 |
-
write = stream.write
|
| 344 |
-
write("bytearray(")
|
| 345 |
-
self._pprint_bytes(
|
| 346 |
-
bytes(object), stream, indent + 10, allowance + 1, context, level + 1
|
| 347 |
-
)
|
| 348 |
-
write(")")
|
| 349 |
-
|
| 350 |
-
_dispatch[bytearray.__repr__] = _pprint_bytearray
|
| 351 |
-
|
| 352 |
-
def _pprint_mappingproxy(
|
| 353 |
-
self,
|
| 354 |
-
object: Any,
|
| 355 |
-
stream: IO[str],
|
| 356 |
-
indent: int,
|
| 357 |
-
allowance: int,
|
| 358 |
-
context: set[int],
|
| 359 |
-
level: int,
|
| 360 |
-
) -> None:
|
| 361 |
-
stream.write("mappingproxy(")
|
| 362 |
-
self._format(object.copy(), stream, indent, allowance, context, level)
|
| 363 |
-
stream.write(")")
|
| 364 |
-
|
| 365 |
-
_dispatch[_types.MappingProxyType.__repr__] = _pprint_mappingproxy
|
| 366 |
-
|
| 367 |
-
def _pprint_simplenamespace(
|
| 368 |
-
self,
|
| 369 |
-
object: Any,
|
| 370 |
-
stream: IO[str],
|
| 371 |
-
indent: int,
|
| 372 |
-
allowance: int,
|
| 373 |
-
context: set[int],
|
| 374 |
-
level: int,
|
| 375 |
-
) -> None:
|
| 376 |
-
if type(object) is _types.SimpleNamespace:
|
| 377 |
-
# The SimpleNamespace repr is "namespace" instead of the class
|
| 378 |
-
# name, so we do the same here. For subclasses; use the class name.
|
| 379 |
-
cls_name = "namespace"
|
| 380 |
-
else:
|
| 381 |
-
cls_name = object.__class__.__name__
|
| 382 |
-
items = object.__dict__.items()
|
| 383 |
-
stream.write(cls_name + "(")
|
| 384 |
-
self._format_namespace_items(items, stream, indent, allowance, context, level)
|
| 385 |
-
stream.write(")")
|
| 386 |
-
|
| 387 |
-
_dispatch[_types.SimpleNamespace.__repr__] = _pprint_simplenamespace
|
| 388 |
-
|
| 389 |
-
def _format_dict_items(
|
| 390 |
-
self,
|
| 391 |
-
items: list[tuple[Any, Any]],
|
| 392 |
-
stream: IO[str],
|
| 393 |
-
indent: int,
|
| 394 |
-
allowance: int,
|
| 395 |
-
context: set[int],
|
| 396 |
-
level: int,
|
| 397 |
-
) -> None:
|
| 398 |
-
if not items:
|
| 399 |
-
return
|
| 400 |
-
|
| 401 |
-
write = stream.write
|
| 402 |
-
item_indent = indent + self._indent_per_level
|
| 403 |
-
delimnl = "\n" + " " * item_indent
|
| 404 |
-
for key, ent in items:
|
| 405 |
-
write(delimnl)
|
| 406 |
-
write(self._repr(key, context, level))
|
| 407 |
-
write(": ")
|
| 408 |
-
self._format(ent, stream, item_indent, 1, context, level)
|
| 409 |
-
write(",")
|
| 410 |
-
|
| 411 |
-
write("\n" + " " * indent)
|
| 412 |
-
|
| 413 |
-
def _format_namespace_items(
|
| 414 |
-
self,
|
| 415 |
-
items: list[tuple[Any, Any]],
|
| 416 |
-
stream: IO[str],
|
| 417 |
-
indent: int,
|
| 418 |
-
allowance: int,
|
| 419 |
-
context: set[int],
|
| 420 |
-
level: int,
|
| 421 |
-
) -> None:
|
| 422 |
-
if not items:
|
| 423 |
-
return
|
| 424 |
-
|
| 425 |
-
write = stream.write
|
| 426 |
-
item_indent = indent + self._indent_per_level
|
| 427 |
-
delimnl = "\n" + " " * item_indent
|
| 428 |
-
for key, ent in items:
|
| 429 |
-
write(delimnl)
|
| 430 |
-
write(key)
|
| 431 |
-
write("=")
|
| 432 |
-
if id(ent) in context:
|
| 433 |
-
# Special-case representation of recursion to match standard
|
| 434 |
-
# recursive dataclass repr.
|
| 435 |
-
write("...")
|
| 436 |
-
else:
|
| 437 |
-
self._format(
|
| 438 |
-
ent,
|
| 439 |
-
stream,
|
| 440 |
-
item_indent + len(key) + 1,
|
| 441 |
-
1,
|
| 442 |
-
context,
|
| 443 |
-
level,
|
| 444 |
-
)
|
| 445 |
-
|
| 446 |
-
write(",")
|
| 447 |
-
|
| 448 |
-
write("\n" + " " * indent)
|
| 449 |
-
|
| 450 |
-
def _format_items(
|
| 451 |
-
self,
|
| 452 |
-
items: list[Any],
|
| 453 |
-
stream: IO[str],
|
| 454 |
-
indent: int,
|
| 455 |
-
allowance: int,
|
| 456 |
-
context: set[int],
|
| 457 |
-
level: int,
|
| 458 |
-
) -> None:
|
| 459 |
-
if not items:
|
| 460 |
-
return
|
| 461 |
-
|
| 462 |
-
write = stream.write
|
| 463 |
-
item_indent = indent + self._indent_per_level
|
| 464 |
-
delimnl = "\n" + " " * item_indent
|
| 465 |
-
|
| 466 |
-
for item in items:
|
| 467 |
-
write(delimnl)
|
| 468 |
-
self._format(item, stream, item_indent, 1, context, level)
|
| 469 |
-
write(",")
|
| 470 |
-
|
| 471 |
-
write("\n" + " " * indent)
|
| 472 |
-
|
| 473 |
-
def _repr(self, object: Any, context: set[int], level: int) -> str:
|
| 474 |
-
return self._safe_repr(object, context.copy(), self._depth, level)
|
| 475 |
-
|
| 476 |
-
def _pprint_default_dict(
|
| 477 |
-
self,
|
| 478 |
-
object: Any,
|
| 479 |
-
stream: IO[str],
|
| 480 |
-
indent: int,
|
| 481 |
-
allowance: int,
|
| 482 |
-
context: set[int],
|
| 483 |
-
level: int,
|
| 484 |
-
) -> None:
|
| 485 |
-
rdf = self._repr(object.default_factory, context, level)
|
| 486 |
-
stream.write(f"{object.__class__.__name__}({rdf}, ")
|
| 487 |
-
self._pprint_dict(object, stream, indent, allowance, context, level)
|
| 488 |
-
stream.write(")")
|
| 489 |
-
|
| 490 |
-
_dispatch[_collections.defaultdict.__repr__] = _pprint_default_dict
|
| 491 |
-
|
| 492 |
-
def _pprint_counter(
|
| 493 |
-
self,
|
| 494 |
-
object: Any,
|
| 495 |
-
stream: IO[str],
|
| 496 |
-
indent: int,
|
| 497 |
-
allowance: int,
|
| 498 |
-
context: set[int],
|
| 499 |
-
level: int,
|
| 500 |
-
) -> None:
|
| 501 |
-
stream.write(object.__class__.__name__ + "(")
|
| 502 |
-
|
| 503 |
-
if object:
|
| 504 |
-
stream.write("{")
|
| 505 |
-
items = object.most_common()
|
| 506 |
-
self._format_dict_items(items, stream, indent, allowance, context, level)
|
| 507 |
-
stream.write("}")
|
| 508 |
-
|
| 509 |
-
stream.write(")")
|
| 510 |
-
|
| 511 |
-
_dispatch[_collections.Counter.__repr__] = _pprint_counter
|
| 512 |
-
|
| 513 |
-
def _pprint_chain_map(
|
| 514 |
-
self,
|
| 515 |
-
object: Any,
|
| 516 |
-
stream: IO[str],
|
| 517 |
-
indent: int,
|
| 518 |
-
allowance: int,
|
| 519 |
-
context: set[int],
|
| 520 |
-
level: int,
|
| 521 |
-
) -> None:
|
| 522 |
-
if not len(object.maps) or (len(object.maps) == 1 and not len(object.maps[0])):
|
| 523 |
-
stream.write(repr(object))
|
| 524 |
-
return
|
| 525 |
-
|
| 526 |
-
stream.write(object.__class__.__name__ + "(")
|
| 527 |
-
self._format_items(object.maps, stream, indent, allowance, context, level)
|
| 528 |
-
stream.write(")")
|
| 529 |
-
|
| 530 |
-
_dispatch[_collections.ChainMap.__repr__] = _pprint_chain_map
|
| 531 |
-
|
| 532 |
-
def _pprint_deque(
|
| 533 |
-
self,
|
| 534 |
-
object: Any,
|
| 535 |
-
stream: IO[str],
|
| 536 |
-
indent: int,
|
| 537 |
-
allowance: int,
|
| 538 |
-
context: set[int],
|
| 539 |
-
level: int,
|
| 540 |
-
) -> None:
|
| 541 |
-
stream.write(object.__class__.__name__ + "(")
|
| 542 |
-
if object.maxlen is not None:
|
| 543 |
-
stream.write(f"maxlen={object.maxlen}, ")
|
| 544 |
-
stream.write("[")
|
| 545 |
-
|
| 546 |
-
self._format_items(object, stream, indent, allowance + 1, context, level)
|
| 547 |
-
stream.write("])")
|
| 548 |
-
|
| 549 |
-
_dispatch[_collections.deque.__repr__] = _pprint_deque
|
| 550 |
-
|
| 551 |
-
def _pprint_user_dict(
|
| 552 |
-
self,
|
| 553 |
-
object: Any,
|
| 554 |
-
stream: IO[str],
|
| 555 |
-
indent: int,
|
| 556 |
-
allowance: int,
|
| 557 |
-
context: set[int],
|
| 558 |
-
level: int,
|
| 559 |
-
) -> None:
|
| 560 |
-
self._format(object.data, stream, indent, allowance, context, level - 1)
|
| 561 |
-
|
| 562 |
-
_dispatch[_collections.UserDict.__repr__] = _pprint_user_dict
|
| 563 |
-
|
| 564 |
-
def _pprint_user_list(
|
| 565 |
-
self,
|
| 566 |
-
object: Any,
|
| 567 |
-
stream: IO[str],
|
| 568 |
-
indent: int,
|
| 569 |
-
allowance: int,
|
| 570 |
-
context: set[int],
|
| 571 |
-
level: int,
|
| 572 |
-
) -> None:
|
| 573 |
-
self._format(object.data, stream, indent, allowance, context, level - 1)
|
| 574 |
-
|
| 575 |
-
_dispatch[_collections.UserList.__repr__] = _pprint_user_list
|
| 576 |
-
|
| 577 |
-
def _pprint_user_string(
|
| 578 |
-
self,
|
| 579 |
-
object: Any,
|
| 580 |
-
stream: IO[str],
|
| 581 |
-
indent: int,
|
| 582 |
-
allowance: int,
|
| 583 |
-
context: set[int],
|
| 584 |
-
level: int,
|
| 585 |
-
) -> None:
|
| 586 |
-
self._format(object.data, stream, indent, allowance, context, level - 1)
|
| 587 |
-
|
| 588 |
-
_dispatch[_collections.UserString.__repr__] = _pprint_user_string
|
| 589 |
-
|
| 590 |
-
def _safe_repr(
|
| 591 |
-
self, object: Any, context: set[int], maxlevels: int | None, level: int
|
| 592 |
-
) -> str:
|
| 593 |
-
typ = type(object)
|
| 594 |
-
if typ in _builtin_scalars:
|
| 595 |
-
return repr(object)
|
| 596 |
-
|
| 597 |
-
r = getattr(typ, "__repr__", None)
|
| 598 |
-
|
| 599 |
-
if issubclass(typ, dict) and r is dict.__repr__:
|
| 600 |
-
if not object:
|
| 601 |
-
return "{}"
|
| 602 |
-
objid = id(object)
|
| 603 |
-
if maxlevels and level >= maxlevels:
|
| 604 |
-
return "{...}"
|
| 605 |
-
if objid in context:
|
| 606 |
-
return _recursion(object)
|
| 607 |
-
context.add(objid)
|
| 608 |
-
components: list[str] = []
|
| 609 |
-
append = components.append
|
| 610 |
-
level += 1
|
| 611 |
-
for k, v in object.items():
|
| 612 |
-
krepr = self._safe_repr(k, context, maxlevels, level)
|
| 613 |
-
vrepr = self._safe_repr(v, context, maxlevels, level)
|
| 614 |
-
append(f"{krepr}: {vrepr}")
|
| 615 |
-
context.remove(objid)
|
| 616 |
-
return "{{{}}}".format(", ".join(components))
|
| 617 |
-
|
| 618 |
-
if (issubclass(typ, list) and r is list.__repr__) or (
|
| 619 |
-
issubclass(typ, tuple) and r is tuple.__repr__
|
| 620 |
-
):
|
| 621 |
-
if issubclass(typ, list):
|
| 622 |
-
if not object:
|
| 623 |
-
return "[]"
|
| 624 |
-
format = "[%s]"
|
| 625 |
-
elif len(object) == 1:
|
| 626 |
-
format = "(%s,)"
|
| 627 |
-
else:
|
| 628 |
-
if not object:
|
| 629 |
-
return "()"
|
| 630 |
-
format = "(%s)"
|
| 631 |
-
objid = id(object)
|
| 632 |
-
if maxlevels and level >= maxlevels:
|
| 633 |
-
return format % "..."
|
| 634 |
-
if objid in context:
|
| 635 |
-
return _recursion(object)
|
| 636 |
-
context.add(objid)
|
| 637 |
-
components = []
|
| 638 |
-
append = components.append
|
| 639 |
-
level += 1
|
| 640 |
-
for o in object:
|
| 641 |
-
orepr = self._safe_repr(o, context, maxlevels, level)
|
| 642 |
-
append(orepr)
|
| 643 |
-
context.remove(objid)
|
| 644 |
-
return format % ", ".join(components)
|
| 645 |
-
|
| 646 |
-
return repr(object)
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
_builtin_scalars = frozenset(
|
| 650 |
-
{str, bytes, bytearray, float, complex, bool, type(None), int}
|
| 651 |
-
)
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
def _recursion(object: Any) -> str:
|
| 655 |
-
return f"<Recursion on {type(object).__name__} with id={id(object)}>"
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
def _wrap_bytes_repr(object: Any, width: int, allowance: int) -> Iterator[str]:
|
| 659 |
-
current = b""
|
| 660 |
-
last = len(object) // 4 * 4
|
| 661 |
-
for i in range(0, len(object), 4):
|
| 662 |
-
part = object[i : i + 4]
|
| 663 |
-
candidate = current + part
|
| 664 |
-
if i == last:
|
| 665 |
-
width -= allowance
|
| 666 |
-
if len(repr(candidate)) > width:
|
| 667 |
-
if current:
|
| 668 |
-
yield repr(current)
|
| 669 |
-
current = part
|
| 670 |
-
else:
|
| 671 |
-
current = candidate
|
| 672 |
-
if current:
|
| 673 |
-
yield repr(current)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|