diff --git a/venv/templates/index.html b/index.html
similarity index 97%
rename from venv/templates/index.html
rename to index.html
index 84544f3..3868b56 100644
--- a/venv/templates/index.html
+++ b/index.html
@@ -56,7 +56,7 @@
diff --git a/venv/static/images/colors/colors.png b/static/images/colors/colors.png
similarity index 100%
rename from venv/static/images/colors/colors.png
rename to static/images/colors/colors.png
diff --git a/venv/static/images/elements/ai/line_long.ai b/static/images/elements/ai/line_long.ai
similarity index 100%
rename from venv/static/images/elements/ai/line_long.ai
rename to static/images/elements/ai/line_long.ai
diff --git a/venv/static/images/elements/ai/line_medium.ai b/static/images/elements/ai/line_medium.ai
similarity index 100%
rename from venv/static/images/elements/ai/line_medium.ai
rename to static/images/elements/ai/line_medium.ai
diff --git a/venv/static/images/elements/ai/line_short.ai b/static/images/elements/ai/line_short.ai
similarity index 100%
rename from venv/static/images/elements/ai/line_short.ai
rename to static/images/elements/ai/line_short.ai
diff --git a/venv/static/images/elements/png/discord.png b/static/images/elements/png/discord.png
similarity index 100%
rename from venv/static/images/elements/png/discord.png
rename to static/images/elements/png/discord.png
diff --git a/venv/static/images/elements/png/github.png b/static/images/elements/png/github.png
similarity index 100%
rename from venv/static/images/elements/png/github.png
rename to static/images/elements/png/github.png
diff --git a/venv/static/images/elements/png/gmail.png b/static/images/elements/png/gmail.png
similarity index 100%
rename from venv/static/images/elements/png/gmail.png
rename to static/images/elements/png/gmail.png
diff --git a/venv/static/images/elements/png/itch.png b/static/images/elements/png/itch.png
similarity index 100%
rename from venv/static/images/elements/png/itch.png
rename to static/images/elements/png/itch.png
diff --git a/venv/static/images/elements/png/line_long.png b/static/images/elements/png/line_long.png
similarity index 100%
rename from venv/static/images/elements/png/line_long.png
rename to static/images/elements/png/line_long.png
diff --git a/venv/static/images/elements/png/line_medium.png b/static/images/elements/png/line_medium.png
similarity index 100%
rename from venv/static/images/elements/png/line_medium.png
rename to static/images/elements/png/line_medium.png
diff --git a/venv/static/images/elements/png/line_short.png b/static/images/elements/png/line_short.png
similarity index 100%
rename from venv/static/images/elements/png/line_short.png
rename to static/images/elements/png/line_short.png
diff --git a/venv/static/images/elements/png/timmy.png b/static/images/elements/png/timmy.png
similarity index 100%
rename from venv/static/images/elements/png/timmy.png
rename to static/images/elements/png/timmy.png
diff --git a/venv/static/images/elements/png/twitter.png b/static/images/elements/png/twitter.png
similarity index 100%
rename from venv/static/images/elements/png/twitter.png
rename to static/images/elements/png/twitter.png
diff --git a/venv/static/images/elements/png/youtube.png b/static/images/elements/png/youtube.png
similarity index 100%
rename from venv/static/images/elements/png/youtube.png
rename to static/images/elements/png/youtube.png
diff --git a/venv/static/images/elements/psd/discord.psd b/static/images/elements/psd/discord.psd
similarity index 100%
rename from venv/static/images/elements/psd/discord.psd
rename to static/images/elements/psd/discord.psd
diff --git a/venv/static/images/elements/psd/github.psd b/static/images/elements/psd/github.psd
similarity index 100%
rename from venv/static/images/elements/psd/github.psd
rename to static/images/elements/psd/github.psd
diff --git a/venv/static/images/elements/psd/gmail.psd b/static/images/elements/psd/gmail.psd
similarity index 100%
rename from venv/static/images/elements/psd/gmail.psd
rename to static/images/elements/psd/gmail.psd
diff --git a/venv/static/images/elements/psd/itch.psd b/static/images/elements/psd/itch.psd
similarity index 100%
rename from venv/static/images/elements/psd/itch.psd
rename to static/images/elements/psd/itch.psd
diff --git a/venv/static/images/elements/psd/twitter.psd b/static/images/elements/psd/twitter.psd
similarity index 100%
rename from venv/static/images/elements/psd/twitter.psd
rename to static/images/elements/psd/twitter.psd
diff --git a/venv/static/images/elements/psd/youtube.psd b/static/images/elements/psd/youtube.psd
similarity index 100%
rename from venv/static/images/elements/psd/youtube.psd
rename to static/images/elements/psd/youtube.psd
diff --git a/venv/static/styles.css b/static/styles.css
similarity index 100%
rename from venv/static/styles.css
rename to static/styles.css
diff --git a/venv/.vercel/README.txt b/venv/.vercel/README.txt
deleted file mode 100644
index 525d8ce..0000000
--- a/venv/.vercel/README.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-> Why do I have a folder named ".vercel" in my project?
-The ".vercel" folder is created when you link a directory to a Vercel project.
-
-> What does the "project.json" file contain?
-The "project.json" file contains:
-- The ID of the Vercel project that you linked ("projectId")
-- The ID of the user or team your Vercel project is owned by ("orgId")
-
-> Should I commit the ".vercel" folder?
-No, you should not share the ".vercel" folder with anyone.
-Upon creation, it will be automatically added to your ".gitignore" file.
diff --git a/venv/.vercel/project.json b/venv/.vercel/project.json
deleted file mode 100644
index 07432c8..0000000
--- a/venv/.vercel/project.json
+++ /dev/null
@@ -1 +0,0 @@
-{"projectId":"prj_fhKjryWYHXc2me4RvhUk0RTMRgSR","orgId":"RXDy9fsHHUMdP3Y9CCzxaa7w"}
\ No newline at end of file
diff --git a/venv/__pycache__/index.cpython-39.pyc b/venv/__pycache__/index.cpython-39.pyc
deleted file mode 100644
index 563b03c..0000000
Binary files a/venv/__pycache__/index.cpython-39.pyc and /dev/null differ
diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1
deleted file mode 100644
index 2fb3852..0000000
--- a/venv/bin/Activate.ps1
+++ /dev/null
@@ -1,241 +0,0 @@
-<#
-.Synopsis
-Activate a Python virtual environment for the current PowerShell session.
-
-.Description
-Pushes the python executable for a virtual environment to the front of the
-$Env:PATH environment variable and sets the prompt to signify that you are
-in a Python virtual environment. Makes use of the command line switches as
-well as the `pyvenv.cfg` file values present in the virtual environment.
-
-.Parameter VenvDir
-Path to the directory that contains the virtual environment to activate. The
-default value for this is the parent of the directory that the Activate.ps1
-script is located within.
-
-.Parameter Prompt
-The prompt prefix to display when this virtual environment is activated. By
-default, this prompt is the name of the virtual environment folder (VenvDir)
-surrounded by parentheses and followed by a single space (ie. '(.venv) ').
-
-.Example
-Activate.ps1
-Activates the Python virtual environment that contains the Activate.ps1 script.
-
-.Example
-Activate.ps1 -Verbose
-Activates the Python virtual environment that contains the Activate.ps1 script,
-and shows extra information about the activation as it executes.
-
-.Example
-Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
-Activates the Python virtual environment located in the specified location.
-
-.Example
-Activate.ps1 -Prompt "MyPython"
-Activates the Python virtual environment that contains the Activate.ps1 script,
-and prefixes the current prompt with the specified string (surrounded in
-parentheses) while the virtual environment is active.
-
-.Notes
-On Windows, it may be required to enable this Activate.ps1 script by setting the
-execution policy for the user. You can do this by issuing the following PowerShell
-command:
-
-PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
-
-For more information on Execution Policies:
-https://go.microsoft.com/fwlink/?LinkID=135170
-
-#>
-Param(
- [Parameter(Mandatory = $false)]
- [String]
- $VenvDir,
- [Parameter(Mandatory = $false)]
- [String]
- $Prompt
-)
-
-<# Function declarations --------------------------------------------------- #>
-
-<#
-.Synopsis
-Remove all shell session elements added by the Activate script, including the
-addition of the virtual environment's Python executable from the beginning of
-the PATH variable.
-
-.Parameter NonDestructive
-If present, do not remove this function from the global namespace for the
-session.
-
-#>
-function global:deactivate ([switch]$NonDestructive) {
- # Revert to original values
-
- # The prior prompt:
- if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
- Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
- Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
- }
-
- # The prior PYTHONHOME:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
- Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
- }
-
- # The prior PATH:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
- Remove-Item -Path Env:_OLD_VIRTUAL_PATH
- }
-
- # Just remove the VIRTUAL_ENV altogether:
- if (Test-Path -Path Env:VIRTUAL_ENV) {
- Remove-Item -Path env:VIRTUAL_ENV
- }
-
- # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
- if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
- Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
- }
-
- # Leave deactivate function in the global namespace if requested:
- if (-not $NonDestructive) {
- Remove-Item -Path function:deactivate
- }
-}
-
-<#
-.Description
-Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
-given folder, and returns them in a map.
-
-For each line in the pyvenv.cfg file, if that line can be parsed into exactly
-two strings separated by `=` (with any amount of whitespace surrounding the =)
-then it is considered a `key = value` line. The left hand string is the key,
-the right hand is the value.
-
-If the value starts with a `'` or a `"` then the first and last character is
-stripped from the value before being captured.
-
-.Parameter ConfigDir
-Path to the directory that contains the `pyvenv.cfg` file.
-#>
-function Get-PyVenvConfig(
- [String]
- $ConfigDir
-) {
- Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
-
- # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
- $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
-
- # An empty map will be returned if no config file is found.
- $pyvenvConfig = @{ }
-
- if ($pyvenvConfigPath) {
-
- Write-Verbose "File exists, parse `key = value` lines"
- $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
-
- $pyvenvConfigContent | ForEach-Object {
- $keyval = $PSItem -split "\s*=\s*", 2
- if ($keyval[0] -and $keyval[1]) {
- $val = $keyval[1]
-
- # Remove extraneous quotations around a string value.
- if ("'""".Contains($val.Substring(0, 1))) {
- $val = $val.Substring(1, $val.Length - 2)
- }
-
- $pyvenvConfig[$keyval[0]] = $val
- Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
- }
- }
- }
- return $pyvenvConfig
-}
-
-
-<# Begin Activate script --------------------------------------------------- #>
-
-# Determine the containing directory of this script
-$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
-$VenvExecDir = Get-Item -Path $VenvExecPath
-
-Write-Verbose "Activation script is located in path: '$VenvExecPath'"
-Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
-Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
-
-# Set values required in priority: CmdLine, ConfigFile, Default
-# First, get the location of the virtual environment, it might not be
-# VenvExecDir if specified on the command line.
-if ($VenvDir) {
- Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
-}
-else {
- Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
- $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
- Write-Verbose "VenvDir=$VenvDir"
-}
-
-# Next, read the `pyvenv.cfg` file to determine any required value such
-# as `prompt`.
-$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
-
-# Next, set the prompt from the command line, or the config file, or
-# just use the name of the virtual environment folder.
-if ($Prompt) {
- Write-Verbose "Prompt specified as argument, using '$Prompt'"
-}
-else {
- Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
- if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
- Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
- $Prompt = $pyvenvCfg['prompt'];
- }
- else {
- Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)"
- Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
- $Prompt = Split-Path -Path $venvDir -Leaf
- }
-}
-
-Write-Verbose "Prompt = '$Prompt'"
-Write-Verbose "VenvDir='$VenvDir'"
-
-# Deactivate any currently active virtual environment, but leave the
-# deactivate function in place.
-deactivate -nondestructive
-
-# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
-# that there is an activated venv.
-$env:VIRTUAL_ENV = $VenvDir
-
-if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
-
- Write-Verbose "Setting prompt to '$Prompt'"
-
- # Set the prompt to include the env name
- # Make sure _OLD_VIRTUAL_PROMPT is global
- function global:_OLD_VIRTUAL_PROMPT { "" }
- Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
- New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
-
- function global:prompt {
- Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
- _OLD_VIRTUAL_PROMPT
- }
-}
-
-# Clear PYTHONHOME
-if (Test-Path -Path Env:PYTHONHOME) {
- Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
- Remove-Item -Path Env:PYTHONHOME
-}
-
-# Add the venv to the PATH
-Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
-$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
diff --git a/venv/bin/activate b/venv/bin/activate
deleted file mode 100644
index 3cefc20..0000000
--- a/venv/bin/activate
+++ /dev/null
@@ -1,66 +0,0 @@
-# This file must be used with "source bin/activate" *from bash*
-# you cannot run it directly
-
-deactivate () {
- # reset old environment variables
- if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
- PATH="${_OLD_VIRTUAL_PATH:-}"
- export PATH
- unset _OLD_VIRTUAL_PATH
- fi
- if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
- PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
- export PYTHONHOME
- unset _OLD_VIRTUAL_PYTHONHOME
- fi
-
- # This should detect bash and zsh, which have a hash command that must
- # be called to get it to forget past commands. Without forgetting
- # past commands the $PATH changes we made may not be respected
- if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
- hash -r 2> /dev/null
- fi
-
- if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
- PS1="${_OLD_VIRTUAL_PS1:-}"
- export PS1
- unset _OLD_VIRTUAL_PS1
- fi
-
- unset VIRTUAL_ENV
- if [ ! "${1:-}" = "nondestructive" ] ; then
- # Self destruct!
- unset -f deactivate
- fi
-}
-
-# unset irrelevant variables
-deactivate nondestructive
-
-VIRTUAL_ENV="/home/timothypidashev/Desktop/Github/Portfolio/venv"
-export VIRTUAL_ENV
-
-_OLD_VIRTUAL_PATH="$PATH"
-PATH="$VIRTUAL_ENV/bin:$PATH"
-export PATH
-
-# unset PYTHONHOME if set
-# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
-# could use `if (set -u; : $PYTHONHOME) ;` in bash
-if [ -n "${PYTHONHOME:-}" ] ; then
- _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
- unset PYTHONHOME
-fi
-
-if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
- _OLD_VIRTUAL_PS1="${PS1:-}"
- PS1="(venv) ${PS1:-}"
- export PS1
-fi
-
-# This should detect bash and zsh, which have a hash command that must
-# be called to get it to forget past commands. Without forgetting
-# past commands the $PATH changes we made may not be respected
-if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
- hash -r 2> /dev/null
-fi
diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh
deleted file mode 100644
index 0664f16..0000000
--- a/venv/bin/activate.csh
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file must be used with "source bin/activate.csh" *from csh*.
-# You cannot run it directly.
-# Created by Davide Di Blasi .
-# Ported to Python 3.3 venv by Andrew Svetlov
-
-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; test "\!:*" != "nondestructive" && unalias deactivate'
-
-# Unset irrelevant variables.
-deactivate nondestructive
-
-setenv VIRTUAL_ENV "/home/timothypidashev/Desktop/Github/Portfolio/venv"
-
-set _OLD_VIRTUAL_PATH="$PATH"
-setenv PATH "$VIRTUAL_ENV/bin:$PATH"
-
-
-set _OLD_VIRTUAL_PROMPT="$prompt"
-
-if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
- set prompt = "(venv) $prompt"
-endif
-
-alias pydoc python -m pydoc
-
-rehash
diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish
deleted file mode 100644
index af07f91..0000000
--- a/venv/bin/activate.fish
+++ /dev/null
@@ -1,64 +0,0 @@
-# This file must be used with "source /bin/activate.fish" *from fish*
-# (https://fishshell.com/); you cannot run it directly.
-
-function deactivate -d "Exit virtual environment and return to normal shell environment"
- # reset old environment variables
- if test -n "$_OLD_VIRTUAL_PATH"
- set -gx PATH $_OLD_VIRTUAL_PATH
- set -e _OLD_VIRTUAL_PATH
- end
- if test -n "$_OLD_VIRTUAL_PYTHONHOME"
- set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
- set -e _OLD_VIRTUAL_PYTHONHOME
- end
-
- if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
- functions -e fish_prompt
- set -e _OLD_FISH_PROMPT_OVERRIDE
- functions -c _old_fish_prompt fish_prompt
- functions -e _old_fish_prompt
- end
-
- set -e VIRTUAL_ENV
- if test "$argv[1]" != "nondestructive"
- # Self-destruct!
- functions -e deactivate
- end
-end
-
-# Unset irrelevant variables.
-deactivate nondestructive
-
-set -gx VIRTUAL_ENV "/home/timothypidashev/Desktop/Github/Portfolio/venv"
-
-set -gx _OLD_VIRTUAL_PATH $PATH
-set -gx PATH "$VIRTUAL_ENV/bin" $PATH
-
-# Unset PYTHONHOME if set.
-if set -q PYTHONHOME
- set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
- set -e PYTHONHOME
-end
-
-if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
- # fish uses a function instead of an env var to generate the prompt.
-
- # Save the current fish_prompt function as the function _old_fish_prompt.
- functions -c fish_prompt _old_fish_prompt
-
- # With the original prompt function renamed, we can override with our own.
- function fish_prompt
- # Save the return status of the last command.
- set -l old_status $status
-
- # Output the venv prompt; color taken from the blue of the Python logo.
- printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal)
-
- # Restore the return status of the previous command.
- echo "exit $old_status" | .
- # Output the original/"old" prompt.
- _old_fish_prompt
- end
-
- set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
-end
diff --git a/venv/bin/easy_install b/venv/bin/easy_install
deleted file mode 100755
index 5bcfd00..0000000
--- a/venv/bin/easy_install
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/timothypidashev/Desktop/Github/Portfolio/venv/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from setuptools.command.easy_install import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/venv/bin/easy_install-3.9 b/venv/bin/easy_install-3.9
deleted file mode 100755
index 5bcfd00..0000000
--- a/venv/bin/easy_install-3.9
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/timothypidashev/Desktop/Github/Portfolio/venv/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from setuptools.command.easy_install import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/venv/bin/flask b/venv/bin/flask
deleted file mode 100755
index 3dd4ec7..0000000
--- a/venv/bin/flask
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/timothypidashev/Desktop/Github/Portfolio/venv/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from flask.cli import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/venv/bin/pip b/venv/bin/pip
deleted file mode 100755
index 90c8b2d..0000000
--- a/venv/bin/pip
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/timothypidashev/Desktop/Github/Portfolio/venv/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from pip._internal.cli.main import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/venv/bin/pip3 b/venv/bin/pip3
deleted file mode 100755
index 90c8b2d..0000000
--- a/venv/bin/pip3
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/timothypidashev/Desktop/Github/Portfolio/venv/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from pip._internal.cli.main import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/venv/bin/pip3.9 b/venv/bin/pip3.9
deleted file mode 100755
index 90c8b2d..0000000
--- a/venv/bin/pip3.9
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/timothypidashev/Desktop/Github/Portfolio/venv/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from pip._internal.cli.main import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/venv/bin/python b/venv/bin/python
deleted file mode 120000
index b8a0adb..0000000
--- a/venv/bin/python
+++ /dev/null
@@ -1 +0,0 @@
-python3
\ No newline at end of file
diff --git a/venv/bin/python3 b/venv/bin/python3
deleted file mode 120000
index ae65fda..0000000
--- a/venv/bin/python3
+++ /dev/null
@@ -1 +0,0 @@
-/usr/bin/python3
\ No newline at end of file
diff --git a/venv/bin/python3.9 b/venv/bin/python3.9
deleted file mode 120000
index b8a0adb..0000000
--- a/venv/bin/python3.9
+++ /dev/null
@@ -1 +0,0 @@
-python3
\ No newline at end of file
diff --git a/venv/index.py b/venv/index.py
deleted file mode 100644
index 8c8384e..0000000
--- a/venv/index.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from flask import Flask, render_template, request
-
-app = Flask(__name__, template_folder = "templates", static_url_path="/static")
-
-#home page
-@app.route("/")
-def index():
- return render_template("index.html")
\ No newline at end of file
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/LICENSE.rst b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/LICENSE.rst
deleted file mode 100644
index 9d227a0..0000000
--- a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/LICENSE.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2010 Pallets
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/METADATA
deleted file mode 100644
index 2b881c2..0000000
--- a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/METADATA
+++ /dev/null
@@ -1,124 +0,0 @@
-Metadata-Version: 2.1
-Name: Flask
-Version: 2.0.1
-Summary: A simple framework for building complex web applications.
-Home-page: https://palletsprojects.com/p/flask
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Donate, https://palletsprojects.com/donate
-Project-URL: Documentation, https://flask.palletsprojects.com/
-Project-URL: Changes, https://flask.palletsprojects.com/changes/
-Project-URL: Source Code, https://github.com/pallets/flask/
-Project-URL: Issue Tracker, https://github.com/pallets/flask/issues/
-Project-URL: Twitter, https://twitter.com/PalletsTeam
-Project-URL: Chat, https://discord.gg/pallets
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Framework :: Flask
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
-Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
-Requires-Python: >=3.6
-Description-Content-Type: text/x-rst
-Requires-Dist: Werkzeug (>=2.0)
-Requires-Dist: Jinja2 (>=3.0)
-Requires-Dist: itsdangerous (>=2.0)
-Requires-Dist: click (>=7.1.2)
-Provides-Extra: async
-Requires-Dist: asgiref (>=3.2) ; extra == 'async'
-Provides-Extra: dotenv
-Requires-Dist: python-dotenv ; extra == 'dotenv'
-
-Flask
-=====
-
-Flask is a lightweight `WSGI`_ web application framework. It is designed
-to make getting started quick and easy, with the ability to scale up to
-complex applications. It began as a simple wrapper around `Werkzeug`_
-and `Jinja`_ and has become one of the most popular Python web
-application frameworks.
-
-Flask offers suggestions, but doesn't enforce any dependencies or
-project layout. It is up to the developer to choose the tools and
-libraries they want to use. There are many extensions provided by the
-community that make adding new functionality easy.
-
-.. _WSGI: https://wsgi.readthedocs.io/
-.. _Werkzeug: https://werkzeug.palletsprojects.com/
-.. _Jinja: https://jinja.palletsprojects.com/
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
- $ pip install -U Flask
-
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
-
-
-A Simple Example
-----------------
-
-.. code-block:: python
-
- # save this as app.py
- from flask import Flask
-
- app = Flask(__name__)
-
- @app.route("/")
- def hello():
- return "Hello, World!"
-
-.. code-block:: text
-
- $ flask run
- * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
-
-
-Contributing
-------------
-
-For guidance on setting up a development environment and how to make a
-contribution to Flask, see the `contributing guidelines`_.
-
-.. _contributing guidelines: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst
-
-
-Donate
-------
-
-The Pallets organization develops and supports Flask and the libraries
-it uses. In order to grow the community of contributors and users, and
-allow the maintainers to devote more time to the projects, `please
-donate today`_.
-
-.. _please donate today: https://palletsprojects.com/donate
-
-
-Links
------
-
-- Documentation: https://flask.palletsprojects.com/
-- Changes: https://flask.palletsprojects.com/changes/
-- PyPI Releases: https://pypi.org/project/Flask/
-- Source Code: https://github.com/pallets/flask/
-- Issue Tracker: https://github.com/pallets/flask/issues/
-- Website: https://palletsprojects.com/p/flask/
-- Twitter: https://twitter.com/PalletsTeam
-- Chat: https://discord.gg/pallets
-
-
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/RECORD
deleted file mode 100644
index b84dba6..0000000
--- a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/RECORD
+++ /dev/null
@@ -1,52 +0,0 @@
-../../../bin/flask,sha256=oKXJDZPqk6BN2kppYhY7euvhskduDexwetAAkeqfyfg,255
-Flask-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-Flask-2.0.1.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
-Flask-2.0.1.dist-info/METADATA,sha256=50Jm1647RKw98p4RF64bCqRh0wajk-n3hQ7av2-pniA,3808
-Flask-2.0.1.dist-info/RECORD,,
-Flask-2.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-Flask-2.0.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
-Flask-2.0.1.dist-info/entry_points.txt,sha256=gBLA1aKg0OYR8AhbAfg8lnburHtKcgJLDU52BBctN0k,42
-Flask-2.0.1.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6
-flask/__init__.py,sha256=w5v6GCNm8eLDMNWqs2ue7HLHo75aslAwz1h3k3YO9HY,2251
-flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
-flask/__pycache__/__init__.cpython-39.pyc,,
-flask/__pycache__/__main__.cpython-39.pyc,,
-flask/__pycache__/app.cpython-39.pyc,,
-flask/__pycache__/blueprints.cpython-39.pyc,,
-flask/__pycache__/cli.cpython-39.pyc,,
-flask/__pycache__/config.cpython-39.pyc,,
-flask/__pycache__/ctx.cpython-39.pyc,,
-flask/__pycache__/debughelpers.cpython-39.pyc,,
-flask/__pycache__/globals.cpython-39.pyc,,
-flask/__pycache__/helpers.cpython-39.pyc,,
-flask/__pycache__/logging.cpython-39.pyc,,
-flask/__pycache__/scaffold.cpython-39.pyc,,
-flask/__pycache__/sessions.cpython-39.pyc,,
-flask/__pycache__/signals.cpython-39.pyc,,
-flask/__pycache__/templating.cpython-39.pyc,,
-flask/__pycache__/testing.cpython-39.pyc,,
-flask/__pycache__/typing.cpython-39.pyc,,
-flask/__pycache__/views.cpython-39.pyc,,
-flask/__pycache__/wrappers.cpython-39.pyc,,
-flask/app.py,sha256=q6lpiiWVxjljQRwjjneUBpfllXYPEq0CFAUpTQ5gIeA,82376
-flask/blueprints.py,sha256=OjI-dkwx96ZNMUGDDFMKzgcpUJf240WRuMlHkmgI1Lc,23541
-flask/cli.py,sha256=iN1pL2SevE5Nmvey-0WwnxG3nipZXIiE__Ed4lx3IuM,32036
-flask/config.py,sha256=jj_7JGen_kYuTlKrx8ZPBsZddb8mihC0ODg4gcjXBX8,11068
-flask/ctx.py,sha256=EM3W0v1ctuFQAGk_HWtQdoJEg_r2f5Le4xcmElxFwwk,17428
-flask/debughelpers.py,sha256=wk5HtLwENsQ4e8tkxfBn6ykUeVRDuMbQCKgtEVe6jxk,6171
-flask/globals.py,sha256=cWd-R2hUH3VqPhnmQNww892tQS6Yjqg_wg8UvW1M7NM,1723
-flask/helpers.py,sha256=00WqA3wYeyjMrnAOPZTUyrnUf7H8ik3CVT0kqGl_qjk,30589
-flask/json/__init__.py,sha256=d-db2DJMASq0G7CI-JvobehRE1asNRGX1rIDQ1GF9WM,11580
-flask/json/__pycache__/__init__.cpython-39.pyc,,
-flask/json/__pycache__/tag.cpython-39.pyc,,
-flask/json/tag.py,sha256=fys3HBLssWHuMAIJuTcf2K0bCtosePBKXIWASZEEjnU,8857
-flask/logging.py,sha256=1o_hirVGqdj7SBdETnhX7IAjklG89RXlrwz_2CjzQQE,2273
-flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-flask/scaffold.py,sha256=EhQuiFrdcmJHxqPGQkEpqLsEUZ7ULZD0rtED2NrduvM,32400
-flask/sessions.py,sha256=Kb7zY4qBIOU2cw1xM5mQ_KmgYUBDFbUYWjlkq0EFYis,15189
-flask/signals.py,sha256=HQWgBEXlrLbHwLBoWqAStJKcN-rsB1_AMO8-VZ7LDOo,2126
-flask/templating.py,sha256=l96VD39JQ0nue4Bcj7wZ4-FWWs-ppLxvgBCpwDQ4KAk,5626
-flask/testing.py,sha256=OsHT-2B70abWH3ulY9IbhLchXIeyj3L-cfcDa88wv5E,10281
-flask/typing.py,sha256=zVqhz53KklncAv-WxbpxGZfaRGOqeWAsLdP1tTMaCuE,1684
-flask/views.py,sha256=F2PpWPloe4x0906IUjnPcsOqg5YvmQIfk07_lFeAD4s,5865
-flask/wrappers.py,sha256=VndbHPRBSUUOejmd2Y3ydkoCVUtsS2OJIdJEVIkBVD8,5604
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/REQUESTED b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/WHEEL
deleted file mode 100644
index 385faab..0000000
--- a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.36.2)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/entry_points.txt
deleted file mode 100644
index 1eb0252..0000000
--- a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/entry_points.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-[console_scripts]
-flask = flask.cli:main
-
diff --git a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/top_level.txt
deleted file mode 100644
index 7e10602..0000000
--- a/venv/lib/python3.9/site-packages/Flask-2.0.1.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-flask
diff --git a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/LICENSE.rst b/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/LICENSE.rst
deleted file mode 100644
index c37cae4..0000000
--- a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/LICENSE.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2007 Pallets
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/METADATA
deleted file mode 100644
index afd84cb..0000000
--- a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/METADATA
+++ /dev/null
@@ -1,112 +0,0 @@
-Metadata-Version: 2.1
-Name: Jinja2
-Version: 3.0.1
-Summary: A very fast and expressive template engine.
-Home-page: https://palletsprojects.com/p/jinja/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Donate, https://palletsprojects.com/donate
-Project-URL: Documentation, https://jinja.palletsprojects.com/
-Project-URL: Changes, https://jinja.palletsprojects.com/changes/
-Project-URL: Source Code, https://github.com/pallets/jinja/
-Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/
-Project-URL: Twitter, https://twitter.com/PalletsTeam
-Project-URL: Chat, https://discord.gg/pallets
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Topic :: Text Processing :: Markup :: HTML
-Requires-Python: >=3.6
-Description-Content-Type: text/x-rst
-Requires-Dist: MarkupSafe (>=2.0)
-Provides-Extra: i18n
-Requires-Dist: Babel (>=2.7) ; extra == 'i18n'
-
-Jinja
-=====
-
-Jinja is a fast, expressive, extensible templating engine. Special
-placeholders in the template allow writing code similar to Python
-syntax. Then the template is passed data to render the final document.
-
-It includes:
-
-- Template inheritance and inclusion.
-- Define and import macros within templates.
-- HTML templates can use autoescaping to prevent XSS from untrusted
- user input.
-- A sandboxed environment can safely render untrusted templates.
-- AsyncIO support for generating templates and calling async
- functions.
-- I18N support with Babel.
-- Templates are compiled to optimized Python code just-in-time and
- cached, or can be compiled ahead-of-time.
-- Exceptions point to the correct line in templates to make debugging
- easier.
-- Extensible filters, tests, functions, and even syntax.
-
-Jinja's philosophy is that while application logic belongs in Python if
-possible, it shouldn't make the template designer's job difficult by
-restricting functionality too much.
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
- $ pip install -U Jinja2
-
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
-
-
-In A Nutshell
--------------
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
- {% block title %}Members{% endblock %}
- {% block content %}
-
- {% endblock %}
-
-
-Donate
-------
-
-The Pallets organization develops and supports Jinja and other popular
-packages. In order to grow the community of contributors and users, and
-allow the maintainers to devote more time to the projects, `please
-donate today`_.
-
-.. _please donate today: https://palletsprojects.com/donate
-
-
-Links
------
-
-- Documentation: https://jinja.palletsprojects.com/
-- Changes: https://jinja.palletsprojects.com/changes/
-- PyPI Releases: https://pypi.org/project/Jinja2/
-- Source Code: https://github.com/pallets/jinja/
-- Issue Tracker: https://github.com/pallets/jinja/issues/
-- Website: https://palletsprojects.com/p/jinja/
-- Twitter: https://twitter.com/PalletsTeam
-- Chat: https://discord.gg/pallets
-
-
diff --git a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/RECORD
deleted file mode 100644
index 4819ff9..0000000
--- a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/RECORD
+++ /dev/null
@@ -1,58 +0,0 @@
-Jinja2-3.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-Jinja2-3.0.1.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
-Jinja2-3.0.1.dist-info/METADATA,sha256=k6STiOONbGESP2rEKmjhznuG10vm9sNCHCUQL9AQFM4,3508
-Jinja2-3.0.1.dist-info/RECORD,,
-Jinja2-3.0.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
-Jinja2-3.0.1.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61
-Jinja2-3.0.1.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7
-jinja2/__init__.py,sha256=fd8jaCRsCATgC7ahuUTD8CyfQoc4aRfALEIny4mwfog,2205
-jinja2/__pycache__/__init__.cpython-39.pyc,,
-jinja2/__pycache__/_identifier.cpython-39.pyc,,
-jinja2/__pycache__/async_utils.cpython-39.pyc,,
-jinja2/__pycache__/bccache.cpython-39.pyc,,
-jinja2/__pycache__/compiler.cpython-39.pyc,,
-jinja2/__pycache__/constants.cpython-39.pyc,,
-jinja2/__pycache__/debug.cpython-39.pyc,,
-jinja2/__pycache__/defaults.cpython-39.pyc,,
-jinja2/__pycache__/environment.cpython-39.pyc,,
-jinja2/__pycache__/exceptions.cpython-39.pyc,,
-jinja2/__pycache__/ext.cpython-39.pyc,,
-jinja2/__pycache__/filters.cpython-39.pyc,,
-jinja2/__pycache__/idtracking.cpython-39.pyc,,
-jinja2/__pycache__/lexer.cpython-39.pyc,,
-jinja2/__pycache__/loaders.cpython-39.pyc,,
-jinja2/__pycache__/meta.cpython-39.pyc,,
-jinja2/__pycache__/nativetypes.cpython-39.pyc,,
-jinja2/__pycache__/nodes.cpython-39.pyc,,
-jinja2/__pycache__/optimizer.cpython-39.pyc,,
-jinja2/__pycache__/parser.cpython-39.pyc,,
-jinja2/__pycache__/runtime.cpython-39.pyc,,
-jinja2/__pycache__/sandbox.cpython-39.pyc,,
-jinja2/__pycache__/tests.cpython-39.pyc,,
-jinja2/__pycache__/utils.cpython-39.pyc,,
-jinja2/__pycache__/visitor.cpython-39.pyc,,
-jinja2/_identifier.py,sha256=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775
-jinja2/async_utils.py,sha256=bY2nCUfBA_4FSnNUsIsJgljBq3hACr6fzLi7LiyMTn8,1751
-jinja2/bccache.py,sha256=smAvSDgDSvXdvJzCN_9s0XfkVpQEu8be-QwgeMlrwiM,12677
-jinja2/compiler.py,sha256=qq0Fo9EpDAEwHPLAs3sAP7dindUvDrFrbx4AcB8xV5M,72046
-jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433
-jinja2/debug.py,sha256=uBmrsiwjYH5l14R9STn5mydOOyriBYol5lDGvEqAb3A,9238
-jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267
-jinja2/environment.py,sha256=T6U4be9mY1CUXXin_EQFwpvpFqCiryweGqzXGRYIoSA,61573
-jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071
-jinja2/ext.py,sha256=44SjDjeYkkxQTpmC2BetOTxEFMgQ42p2dfSwXmPFcSo,32122
-jinja2/filters.py,sha256=LslRsJd0JVFBHtdfU_WraM1eQitotciwawiW-seR42U,52577
-jinja2/idtracking.py,sha256=KdFVohVNK-baOwt_INPMco19D7AfLDEN8i3_JoiYnGQ,10713
-jinja2/lexer.py,sha256=D5qOKB3KnRqK9gPAZFQvRguomYsQok5-14TKiWTN8Jw,29923
-jinja2/loaders.py,sha256=ePpWB0xDrILgLVqNFcxqqSbPizsI0T-JlkNEUFqq9fo,22350
-jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396
-jinja2/nativetypes.py,sha256=62hvvsAxAj0YaxylOHoREYVogJ5JqOlJISgGY3OKd_o,3675
-jinja2/nodes.py,sha256=LHF97fu6GW4r2Z9UaOX92MOT1wZpdS9Nx4N-5Fp5ti8,34509
-jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650
-jinja2/parser.py,sha256=kHnU8v92GwMYkfr0MVakWv8UlSf_kJPx8LUsgQMof70,39767
-jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-jinja2/runtime.py,sha256=bSWdawLjReKpKHhF3-96OIuWYpUy1yxFJCN3jBYyoXc,35013
-jinja2/sandbox.py,sha256=-8zxR6TO9kUkciAVFsIKu8Oq-C7PTeYEdZ5TtA55-gw,14600
-jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905
-jinja2/utils.py,sha256=0wGkxDbxlW10y0ac4-kEiy1Bn0AsWXqz8uomK9Ugy1Q,26961
-jinja2/visitor.py,sha256=ZmeLuTj66ic35-uFH-1m0EKXiw4ObDDb_WuE6h5vPFg,3572
diff --git a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/WHEEL
deleted file mode 100644
index 385faab..0000000
--- a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.36.2)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/entry_points.txt b/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/entry_points.txt
deleted file mode 100644
index 3619483..0000000
--- a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/entry_points.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-[babel.extractors]
-jinja2 = jinja2.ext:babel_extract [i18n]
-
diff --git a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/top_level.txt
deleted file mode 100644
index 7f7afbf..0000000
--- a/venv/lib/python3.9/site-packages/Jinja2-3.0.1.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-jinja2
diff --git a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/LICENSE.rst b/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/LICENSE.rst
deleted file mode 100644
index 9d227a0..0000000
--- a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/LICENSE.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2010 Pallets
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/METADATA
deleted file mode 100644
index ef44e2b..0000000
--- a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/METADATA
+++ /dev/null
@@ -1,100 +0,0 @@
-Metadata-Version: 2.1
-Name: MarkupSafe
-Version: 2.0.1
-Summary: Safely add untrusted strings to HTML/XML markup.
-Home-page: https://palletsprojects.com/p/markupsafe/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Donate, https://palletsprojects.com/donate
-Project-URL: Documentation, https://markupsafe.palletsprojects.com/
-Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/
-Project-URL: Source Code, https://github.com/pallets/markupsafe/
-Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/
-Project-URL: Twitter, https://twitter.com/PalletsTeam
-Project-URL: Chat, https://discord.gg/pallets
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Topic :: Text Processing :: Markup :: HTML
-Requires-Python: >=3.6
-Description-Content-Type: text/x-rst
-
-MarkupSafe
-==========
-
-MarkupSafe implements a text object that escapes characters so it is
-safe to use in HTML and XML. Characters that have special meanings are
-replaced so that they display as the actual characters. This mitigates
-injection attacks, meaning untrusted user input can safely be displayed
-on a page.
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
- pip install -U MarkupSafe
-
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
-
-
-Examples
---------
-
-.. code-block:: pycon
-
- >>> from markupsafe import Markup, escape
-
- >>> # escape replaces special characters and wraps in Markup
- >>> escape("")
- Markup('<script>alert(document.cookie);</script>')
-
- >>> # wrap in Markup to mark text "safe" and prevent escaping
- >>> Markup("Hello")
- Markup('hello')
-
- >>> escape(Markup("Hello"))
- Markup('hello')
-
- >>> # Markup is a str subclass
- >>> # methods and operators escape their arguments
- >>> template = Markup("Hello {name}")
- >>> template.format(name='"World"')
- Markup('Hello "World"')
-
-
-Donate
-------
-
-The Pallets organization develops and supports MarkupSafe and other
-popular packages. In order to grow the community of contributors and
-users, and allow the maintainers to devote more time to the projects,
-`please donate today`_.
-
-.. _please donate today: https://palletsprojects.com/donate
-
-
-Links
------
-
-- Documentation: https://markupsafe.palletsprojects.com/
-- Changes: https://markupsafe.palletsprojects.com/changes/
-- PyPI Releases: https://pypi.org/project/MarkupSafe/
-- Source Code: https://github.com/pallets/markupsafe/
-- Issue Tracker: https://github.com/pallets/markupsafe/issues/
-- Website: https://palletsprojects.com/p/markupsafe/
-- Twitter: https://twitter.com/PalletsTeam
-- Chat: https://discord.gg/pallets
-
-
diff --git a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/RECORD
deleted file mode 100644
index 6fba495..0000000
--- a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/RECORD
+++ /dev/null
@@ -1,14 +0,0 @@
-MarkupSafe-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-MarkupSafe-2.0.1.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
-MarkupSafe-2.0.1.dist-info/METADATA,sha256=FmPpxBdaqCCjF-XKqoxeEzqAzhetQnrkkSsd3V3X-Jc,3211
-MarkupSafe-2.0.1.dist-info/RECORD,,
-MarkupSafe-2.0.1.dist-info/WHEEL,sha256=C-sg6l2ppbqlkU_0fUt0o5fTSvsM-h9TfVKAh4ryMfI,111
-MarkupSafe-2.0.1.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
-markupsafe/__init__.py,sha256=9Tez4UIlI7J6_sQcUFK1dKniT_b_8YefpGIyYJ3Sr2Q,8923
-markupsafe/__pycache__/__init__.cpython-39.pyc,,
-markupsafe/__pycache__/_native.cpython-39.pyc,,
-markupsafe/_native.py,sha256=GTKEV-bWgZuSjklhMHOYRHU9k0DMewTf5mVEZfkbuns,1986
-markupsafe/_speedups.c,sha256=CDDtwaV21D2nYtypnMQzxvvpZpcTvIs8OZ6KDa1g4t0,7400
-markupsafe/_speedups.cpython-39-x86_64-linux-gnu.so,sha256=eGr-sqbWsXEBzb2iypAevZQXZFzkverTnd_GX5lvgnM,53224
-markupsafe/_speedups.pyi,sha256=vfMCsOgbAXRNLUXkyuyonG8uEWKYU4PDqNuMaDELAYw,229
-markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
diff --git a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/WHEEL
deleted file mode 100644
index a98f911..0000000
--- a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.36.2)
-Root-Is-Purelib: false
-Tag: cp39-cp39-manylinux2010_x86_64
-
diff --git a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/top_level.txt
deleted file mode 100644
index 75bf729..0000000
--- a/venv/lib/python3.9/site-packages/MarkupSafe-2.0.1.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-markupsafe
diff --git a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/LICENSE.rst b/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/LICENSE.rst
deleted file mode 100644
index c37cae4..0000000
--- a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/LICENSE.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2007 Pallets
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/METADATA
deleted file mode 100644
index f991d5a..0000000
--- a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/METADATA
+++ /dev/null
@@ -1,128 +0,0 @@
-Metadata-Version: 2.1
-Name: Werkzeug
-Version: 2.0.1
-Summary: The comprehensive WSGI web application library.
-Home-page: https://palletsprojects.com/p/werkzeug/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Donate, https://palletsprojects.com/donate
-Project-URL: Documentation, https://werkzeug.palletsprojects.com/
-Project-URL: Changes, https://werkzeug.palletsprojects.com/changes/
-Project-URL: Source Code, https://github.com/pallets/werkzeug/
-Project-URL: Issue Tracker, https://github.com/pallets/werkzeug/issues/
-Project-URL: Twitter, https://twitter.com/PalletsTeam
-Project-URL: Chat, https://discord.gg/pallets
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
-Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
-Requires-Python: >=3.6
-Description-Content-Type: text/x-rst
-Requires-Dist: dataclasses ; python_version < "3.7"
-Provides-Extra: watchdog
-Requires-Dist: watchdog ; extra == 'watchdog'
-
-Werkzeug
-========
-
-*werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff")
-
-Werkzeug is a comprehensive `WSGI`_ web application library. It began as
-a simple collection of various utilities for WSGI applications and has
-become one of the most advanced WSGI utility libraries.
-
-It includes:
-
-- An interactive debugger that allows inspecting stack traces and
- source code in the browser with an interactive interpreter for any
- frame in the stack.
-- A full-featured request object with objects to interact with
- headers, query args, form data, files, and cookies.
-- A response object that can wrap other WSGI applications and handle
- streaming data.
-- A routing system for matching URLs to endpoints and generating URLs
- for endpoints, with an extensible system for capturing variables
- from URLs.
-- HTTP utilities to handle entity tags, cache control, dates, user
- agents, cookies, files, and more.
-- A threaded WSGI server for use while developing applications
- locally.
-- A test client for simulating HTTP requests during testing without
- requiring running a server.
-
-Werkzeug doesn't enforce any dependencies. It is up to the developer to
-choose a template engine, database adapter, and even how to handle
-requests. It can be used to build all sorts of end user applications
-such as blogs, wikis, or bulletin boards.
-
-`Flask`_ wraps Werkzeug, using it to handle the details of WSGI while
-providing more structure and patterns for defining powerful
-applications.
-
-.. _WSGI: https://wsgi.readthedocs.io/en/latest/
-.. _Flask: https://www.palletsprojects.com/p/flask/
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
- pip install -U Werkzeug
-
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
-
-
-A Simple Example
-----------------
-
-.. code-block:: python
-
- from werkzeug.wrappers import Request, Response
-
- @Request.application
- def application(request):
- return Response('Hello, World!')
-
- if __name__ == '__main__':
- from werkzeug.serving import run_simple
- run_simple('localhost', 4000, application)
-
-
-Donate
-------
-
-The Pallets organization develops and supports Werkzeug and other
-popular packages. In order to grow the community of contributors and
-users, and allow the maintainers to devote more time to the projects,
-`please donate today`_.
-
-.. _please donate today: https://palletsprojects.com/donate
-
-
-Links
------
-
-- Documentation: https://werkzeug.palletsprojects.com/
-- Changes: https://werkzeug.palletsprojects.com/changes/
-- PyPI Releases: https://pypi.org/project/Werkzeug/
-- Source Code: https://github.com/pallets/werkzeug/
-- Issue Tracker: https://github.com/pallets/werkzeug/issues/
-- Website: https://palletsprojects.com/p/werkzeug/
-- Twitter: https://twitter.com/PalletsTeam
-- Chat: https://discord.gg/pallets
-
-
diff --git a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/RECORD
deleted file mode 100644
index 960fd52..0000000
--- a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/RECORD
+++ /dev/null
@@ -1,111 +0,0 @@
-Werkzeug-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-Werkzeug-2.0.1.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
-Werkzeug-2.0.1.dist-info/METADATA,sha256=8-W33EMnGqnCCi-d8Dv63IQQuyELRIsXhwOJNXbNgL0,4421
-Werkzeug-2.0.1.dist-info/RECORD,,
-Werkzeug-2.0.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
-Werkzeug-2.0.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9
-werkzeug/__init__.py,sha256=_CCsfdeqNllFNRJx8cvqYrwBsQQQXJaMmnk2sAZnDng,188
-werkzeug/__pycache__/__init__.cpython-39.pyc,,
-werkzeug/__pycache__/_internal.cpython-39.pyc,,
-werkzeug/__pycache__/_reloader.cpython-39.pyc,,
-werkzeug/__pycache__/datastructures.cpython-39.pyc,,
-werkzeug/__pycache__/exceptions.cpython-39.pyc,,
-werkzeug/__pycache__/filesystem.cpython-39.pyc,,
-werkzeug/__pycache__/formparser.cpython-39.pyc,,
-werkzeug/__pycache__/http.cpython-39.pyc,,
-werkzeug/__pycache__/local.cpython-39.pyc,,
-werkzeug/__pycache__/routing.cpython-39.pyc,,
-werkzeug/__pycache__/security.cpython-39.pyc,,
-werkzeug/__pycache__/serving.cpython-39.pyc,,
-werkzeug/__pycache__/test.cpython-39.pyc,,
-werkzeug/__pycache__/testapp.cpython-39.pyc,,
-werkzeug/__pycache__/urls.cpython-39.pyc,,
-werkzeug/__pycache__/user_agent.cpython-39.pyc,,
-werkzeug/__pycache__/useragents.cpython-39.pyc,,
-werkzeug/__pycache__/utils.cpython-39.pyc,,
-werkzeug/__pycache__/wsgi.cpython-39.pyc,,
-werkzeug/_internal.py,sha256=_QKkvdaG4pDFwK68c0EpPzYJGe9Y7toRAT1cBbC-CxU,18572
-werkzeug/_reloader.py,sha256=B1hEfgsUOz2IginBQM5Zak_eaIF7gr3GS5-0x2OHvAE,13950
-werkzeug/datastructures.py,sha256=KahVPSLOapbNbKh1ppr9K8_DgWJv1EGgA9DhTEGMHcg,97886
-werkzeug/datastructures.pyi,sha256=5DTPF8P8Zvi458eK27Qcj7eNUlLM_AC0jBNkj6uQpds,33774
-werkzeug/debug/__init__.py,sha256=CUFrPEYAaotHRkmjOieqd3EasXDii2JVC1HdmEzMwqM,17924
-werkzeug/debug/__pycache__/__init__.cpython-39.pyc,,
-werkzeug/debug/__pycache__/console.cpython-39.pyc,,
-werkzeug/debug/__pycache__/repr.cpython-39.pyc,,
-werkzeug/debug/__pycache__/tbtools.cpython-39.pyc,,
-werkzeug/debug/console.py,sha256=E1nBMEvFkX673ShQjPtVY-byYatfX9MN-dBMjRI8a8E,5897
-werkzeug/debug/repr.py,sha256=QCSHENKsChEZDCIApkVi_UNjhJ77v8BMXK1OfxO189M,9483
-werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673
-werkzeug/debug/shared/ICON_LICENSE.md,sha256=DhA6Y1gUl5Jwfg0NFN9Rj4VWITt8tUx0IvdGf0ux9-s,222
-werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507
-werkzeug/debug/shared/debugger.js,sha256=dYbUmFmb3YZb5YpWpYPOQArdrN7NPeY0ODawL7ihzDI,10524
-werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191
-werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200
-werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818
-werkzeug/debug/shared/style.css,sha256=vyp1RnB227Fuw8LIyM5C-bBCBQN5hvZSCApY2oeJ9ik,6705
-werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220
-werkzeug/debug/tbtools.py,sha256=TfReusPbM3yjm3xvOFkH45V7-5JnNqB9x1EQPnVC6Xo,19189
-werkzeug/exceptions.py,sha256=CUwx0pBiNbk4f9cON17ekgKnmLi6HIVFjUmYZc2x0wM,28681
-werkzeug/filesystem.py,sha256=JS2Dv2QF98WILxY4_thHl-WMcUcwluF_4igkDPaP1l4,1956
-werkzeug/formparser.py,sha256=GIKfzuQ_khuBXnf3N7_LzOEruYwNc3m4bI02BgtT5jg,17385
-werkzeug/http.py,sha256=oUCXFFMnkOQ-cHbUY_aiqitshcrSzNDq3fEMf1VI_yk,45141
-werkzeug/local.py,sha256=WsR6H-2XOtPigpimjORbLsS3h9WI0lCdZjGI2LHDDxA,22733
-werkzeug/middleware/__init__.py,sha256=qfqgdT5npwG9ses3-FXQJf3aB95JYP1zchetH_T3PUw,500
-werkzeug/middleware/__pycache__/__init__.cpython-39.pyc,,
-werkzeug/middleware/__pycache__/dispatcher.cpython-39.pyc,,
-werkzeug/middleware/__pycache__/http_proxy.cpython-39.pyc,,
-werkzeug/middleware/__pycache__/lint.cpython-39.pyc,,
-werkzeug/middleware/__pycache__/profiler.cpython-39.pyc,,
-werkzeug/middleware/__pycache__/proxy_fix.cpython-39.pyc,,
-werkzeug/middleware/__pycache__/shared_data.cpython-39.pyc,,
-werkzeug/middleware/dispatcher.py,sha256=Fh_w-KyWnTSYF-Lfv5dimQ7THSS7afPAZMmvc4zF1gg,2580
-werkzeug/middleware/http_proxy.py,sha256=HE8VyhS7CR-E1O6_9b68huv8FLgGGR1DLYqkS3Xcp3Q,7558
-werkzeug/middleware/lint.py,sha256=yMzMdm4xI2_N-Wv2j1yoaVI3ltHOYS6yZyA-wUv1sKw,13962
-werkzeug/middleware/profiler.py,sha256=G2JieUMv4QPamtCY6ibIK7P-piPRdPybav7bm2MSFvs,4898
-werkzeug/middleware/proxy_fix.py,sha256=uRgQ3dEvFV8JxUqajHYYYOPEeA_BFqaa51Yp8VW0uzA,6849
-werkzeug/middleware/shared_data.py,sha256=eOCGr-i6BCexDfL7xdPRWMwPJPgp0NE2B416Gl67Q78,10959
-werkzeug/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-werkzeug/routing.py,sha256=FDRtvCfaZSmXnQ0cUYxowb3P0y0dxlUlMSUmerY5sb0,84147
-werkzeug/sansio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-werkzeug/sansio/__pycache__/__init__.cpython-39.pyc,,
-werkzeug/sansio/__pycache__/multipart.cpython-39.pyc,,
-werkzeug/sansio/__pycache__/request.cpython-39.pyc,,
-werkzeug/sansio/__pycache__/response.cpython-39.pyc,,
-werkzeug/sansio/__pycache__/utils.cpython-39.pyc,,
-werkzeug/sansio/multipart.py,sha256=bJMCNC2f5xyAaylahNViJ0JqmV4ThLRbDVGVzKwcqrQ,8751
-werkzeug/sansio/request.py,sha256=aA9rABkWiG4MhYMByanst2NXkEclsq8SIxhb0LQf0e0,20228
-werkzeug/sansio/response.py,sha256=HSG6t-tyPZd3awzWqr7qL9IV4HYAvDgON1c0YPU2RXw,24117
-werkzeug/sansio/utils.py,sha256=V5v-UUnX8pm4RehP9Tt_NiUSOJGJGUvKjlW0eOIQldM,4164
-werkzeug/security.py,sha256=gPDRuCjkjWrcqj99tBMq8_nHFZLFQjgoW5Ga5XIw9jo,8158
-werkzeug/serving.py,sha256=_RG2dCclOQcdjJ2NE8tzCRybGePlwcs8kTypiWRP2gY,38030
-werkzeug/test.py,sha256=EJXJy-b_JriHrlfs5VNCkwbki8Kn_xUDkOYOCx_6Q7Q,48096
-werkzeug/testapp.py,sha256=f48prWSGJhbSrvYb8e1fnAah4BkrLb0enHSdChgsjBY,9471
-werkzeug/urls.py,sha256=3o_aUcr5Ou13XihSU6VvX6RHMhoWkKpXuCCia9SSAb8,41021
-werkzeug/user_agent.py,sha256=WclZhpvgLurMF45hsioSbS75H1Zb4iMQGKN3_yZ2oKo,1420
-werkzeug/useragents.py,sha256=G8tmv_6vxJaPrLQH3eODNgIYe0_V6KETROQlJI-WxDE,7264
-werkzeug/utils.py,sha256=WrU-LbwemyGd8zBHBgQyLaIxing4QLEChiP0qnzr2sc,36771
-werkzeug/wrappers/__init__.py,sha256=-s75nPbyXHzU_rwmLPDhoMuGbEUk0jZT_n0ZQAOFGf8,654
-werkzeug/wrappers/__pycache__/__init__.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/accept.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/auth.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/base_request.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/base_response.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/common_descriptors.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/cors.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/etag.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/json.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/request.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/response.cpython-39.pyc,,
-werkzeug/wrappers/__pycache__/user_agent.cpython-39.pyc,,
-werkzeug/wrappers/accept.py,sha256=_oZtAQkahvsrPRkNj2fieg7_St9P0NFC3SgZbJKS6xU,429
-werkzeug/wrappers/auth.py,sha256=rZPCzGxHk9R55PRkmS90kRywUVjjuMWzCGtH68qCq8U,856
-werkzeug/wrappers/base_request.py,sha256=saz9RyNQkvI_XLPYVm29KijNHmD1YzgxDqa0qHTbgss,1174
-werkzeug/wrappers/base_response.py,sha256=q_-TaYywT5G4zA-DWDRDJhJSat2_4O7gOPob6ye4_9A,1186
-werkzeug/wrappers/common_descriptors.py,sha256=v_kWLH3mvCiSRVJ1FNw7nO3w2UJfzY57UKKB5J4zCvE,898
-werkzeug/wrappers/cors.py,sha256=c5UndlZsZvYkbPrp6Gj5iSXxw_VOJDJHskO6-jRmNyQ,846
-werkzeug/wrappers/etag.py,sha256=XHWQQs7Mdd1oWezgBIsl-bYe8ydKkRZVil2Qd01D0Mo,846
-werkzeug/wrappers/json.py,sha256=HM1btPseGeXca0vnwQN_MvZl6h-qNsFY5YBKXKXFwus,410
-werkzeug/wrappers/request.py,sha256=0zAkCUwJbUBzioGy2UKxE6XpuXPAZbEhhML4WErzeBo,24818
-werkzeug/wrappers/response.py,sha256=95hXIysZTeNC0bqhvGB2fLBRKxedR_cgI5szZZWfyzw,35177
-werkzeug/wrappers/user_agent.py,sha256=Wl1-A0-1r8o7cHIZQTB55O4Ged6LpCKENaQDlOY5pXA,435
-werkzeug/wsgi.py,sha256=7psV3SHLtCzk1KSuGmIK5uP2QTDXyfCCDclyqCmIUO4,33715
diff --git a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/WHEEL
deleted file mode 100644
index 385faab..0000000
--- a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.36.2)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/top_level.txt
deleted file mode 100644
index 6fe8da8..0000000
--- a/venv/lib/python3.9/site-packages/Werkzeug-2.0.1.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-werkzeug
diff --git a/venv/lib/python3.9/site-packages/__pycache__/easy_install.cpython-39.pyc b/venv/lib/python3.9/site-packages/__pycache__/easy_install.cpython-39.pyc
deleted file mode 100644
index 52cb6fd..0000000
Binary files a/venv/lib/python3.9/site-packages/__pycache__/easy_install.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/INSTALLER b/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/LICENSE.rst b/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/LICENSE.rst
deleted file mode 100644
index d12a849..0000000
--- a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/LICENSE.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2014 Pallets
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/METADATA b/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/METADATA
deleted file mode 100644
index 7be0832..0000000
--- a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/METADATA
+++ /dev/null
@@ -1,110 +0,0 @@
-Metadata-Version: 2.1
-Name: click
-Version: 8.0.1
-Summary: Composable command line interface toolkit
-Home-page: https://palletsprojects.com/p/click/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Donate, https://palletsprojects.com/donate
-Project-URL: Documentation, https://click.palletsprojects.com/
-Project-URL: Changes, https://click.palletsprojects.com/changes/
-Project-URL: Source Code, https://github.com/pallets/click/
-Project-URL: Issue Tracker, https://github.com/pallets/click/issues/
-Project-URL: Twitter, https://twitter.com/PalletsTeam
-Project-URL: Chat, https://discord.gg/pallets
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Requires-Python: >=3.6
-Description-Content-Type: text/x-rst
-Requires-Dist: colorama ; platform_system == "Windows"
-Requires-Dist: importlib-metadata ; python_version < "3.8"
-
-\$ click\_
-==========
-
-Click is a Python package for creating beautiful command line interfaces
-in a composable way with as little code as necessary. It's the "Command
-Line Interface Creation Kit". It's highly configurable but comes with
-sensible defaults out of the box.
-
-It aims to make the process of writing command line tools quick and fun
-while also preventing any frustration caused by the inability to
-implement an intended CLI API.
-
-Click in three points:
-
-- Arbitrary nesting of commands
-- Automatic help page generation
-- Supports lazy loading of subcommands at runtime
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
- $ pip install -U click
-
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
-
-
-A Simple Example
-----------------
-
-.. code-block:: python
-
- import click
-
- @click.command()
- @click.option("--count", default=1, help="Number of greetings.")
- @click.option("--name", prompt="Your name", help="The person to greet.")
- def hello(count, name):
- """Simple program that greets NAME for a total of COUNT times."""
- for _ in range(count):
- click.echo(f"Hello, {name}!")
-
- if __name__ == '__main__':
- hello()
-
-.. code-block:: text
-
- $ python hello.py --count=3
- Your name: Click
- Hello, Click!
- Hello, Click!
- Hello, Click!
-
-
-Donate
-------
-
-The Pallets organization develops and supports Click and other popular
-packages. In order to grow the community of contributors and users, and
-allow the maintainers to devote more time to the projects, `please
-donate today`_.
-
-.. _please donate today: https://palletsprojects.com/donate
-
-
-Links
------
-
-- Documentation: https://click.palletsprojects.com/
-- Changes: https://click.palletsprojects.com/changes/
-- PyPI Releases: https://pypi.org/project/click/
-- Source Code: https://github.com/pallets/click
-- Issue Tracker: https://github.com/pallets/click/issues
-- Website: https://palletsprojects.com/p/click
-- Twitter: https://twitter.com/PalletsTeam
-- Chat: https://discord.gg/pallets
-
-
diff --git a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/RECORD b/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/RECORD
deleted file mode 100644
index 0fa14e7..0000000
--- a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/RECORD
+++ /dev/null
@@ -1,41 +0,0 @@
-click-8.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-click-8.0.1.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475
-click-8.0.1.dist-info/METADATA,sha256=Q_8tjC_Ps-9OmIDcovMWvqzrNlmYNwJ7yZxyeJ-SIsk,3216
-click-8.0.1.dist-info/RECORD,,
-click-8.0.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
-click-8.0.1.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6
-click/__init__.py,sha256=TweMqq3qEdmxSl3M_O0H1crtKtd7_oS7PDd0WlLote0,3243
-click/__pycache__/__init__.cpython-39.pyc,,
-click/__pycache__/_compat.cpython-39.pyc,,
-click/__pycache__/_termui_impl.cpython-39.pyc,,
-click/__pycache__/_textwrap.cpython-39.pyc,,
-click/__pycache__/_unicodefun.cpython-39.pyc,,
-click/__pycache__/_winconsole.cpython-39.pyc,,
-click/__pycache__/core.cpython-39.pyc,,
-click/__pycache__/decorators.cpython-39.pyc,,
-click/__pycache__/exceptions.cpython-39.pyc,,
-click/__pycache__/formatting.cpython-39.pyc,,
-click/__pycache__/globals.cpython-39.pyc,,
-click/__pycache__/parser.cpython-39.pyc,,
-click/__pycache__/shell_completion.cpython-39.pyc,,
-click/__pycache__/termui.cpython-39.pyc,,
-click/__pycache__/testing.cpython-39.pyc,,
-click/__pycache__/types.cpython-39.pyc,,
-click/__pycache__/utils.cpython-39.pyc,,
-click/_compat.py,sha256=P15KQumAZC2F2MFe_JSRbvVOJcNosQfMDrdZq0ReCLM,18814
-click/_termui_impl.py,sha256=3IBc-wR8art7cOIN3y4vQ3ftyCs4GNLMjDcrSalUD9c,23423
-click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353
-click/_unicodefun.py,sha256=JKSh1oSwG_zbjAu4TBCa9tQde2P9FiYcf4MBfy5NdT8,3201
-click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860
-click/core.py,sha256=xYDxID7ShkgY2Lbw7vKOMjP5ImT1NLCTqMJphUicAQ0,111335
-click/decorators.py,sha256=u_Ehdo3PA2nzCoud9z6fGhxwtMI8vVNG_SL8Bl9lsnY,14871
-click/exceptions.py,sha256=7gDaLGuFZBeCNwY9ERMsF2-Z3R9Fvq09Zc6IZSKjseo,9167
-click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706
-click/globals.py,sha256=9pcmaNfGS1bJV5DoFYhfv51BPeHP8dWaya7rP3kcrY4,1973
-click/parser.py,sha256=x5DbnBV9O8kXiMdJAdtpdTO2eRUXw2ab5PRMLxo0po4,19043
-click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-click/shell_completion.py,sha256=F0CHHFOP4ulDsYoqTMm9FXih_OVKsg3mzD-XBzMN79c,17881
-click/termui.py,sha256=MJNkEntRiNZvwa0z9SVK0d6X9BvUcFhvxKky5M-kBGY,28809
-click/testing.py,sha256=kLR5Qcny1OlgxaGB3gweTr0gQe1yVlmgQRn2esA2Fz4,16020
-click/types.py,sha256=ngn3qOaHcDvyeMF2UT5QJNNpJAAVrA9BRj4t8x1xOZM,35375
-click/utils.py,sha256=q7xUTlebAnIENo2Uv-REArW_erqGFm_8yMW241mMjzQ,18752
diff --git a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/WHEEL b/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/WHEEL
deleted file mode 100644
index 385faab..0000000
--- a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.36.2)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/top_level.txt b/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/top_level.txt
deleted file mode 100644
index dca9a90..0000000
--- a/venv/lib/python3.9/site-packages/click-8.0.1.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-click
diff --git a/venv/lib/python3.9/site-packages/click/__init__.py b/venv/lib/python3.9/site-packages/click/__init__.py
deleted file mode 100644
index 9e0afb2..0000000
--- a/venv/lib/python3.9/site-packages/click/__init__.py
+++ /dev/null
@@ -1,75 +0,0 @@
-"""
-Click is a simple Python module inspired by the stdlib optparse to make
-writing command line scripts fun. Unlike other modules, it's based
-around a simple API that does not come with too much magic and is
-composable.
-"""
-from .core import Argument as Argument
-from .core import BaseCommand as BaseCommand
-from .core import Command as Command
-from .core import CommandCollection as CommandCollection
-from .core import Context as Context
-from .core import Group as Group
-from .core import MultiCommand as MultiCommand
-from .core import Option as Option
-from .core import Parameter as Parameter
-from .decorators import argument as argument
-from .decorators import command as command
-from .decorators import confirmation_option as confirmation_option
-from .decorators import group as group
-from .decorators import help_option as help_option
-from .decorators import make_pass_decorator as make_pass_decorator
-from .decorators import option as option
-from .decorators import pass_context as pass_context
-from .decorators import pass_obj as pass_obj
-from .decorators import password_option as password_option
-from .decorators import version_option as version_option
-from .exceptions import Abort as Abort
-from .exceptions import BadArgumentUsage as BadArgumentUsage
-from .exceptions import BadOptionUsage as BadOptionUsage
-from .exceptions import BadParameter as BadParameter
-from .exceptions import ClickException as ClickException
-from .exceptions import FileError as FileError
-from .exceptions import MissingParameter as MissingParameter
-from .exceptions import NoSuchOption as NoSuchOption
-from .exceptions import UsageError as UsageError
-from .formatting import HelpFormatter as HelpFormatter
-from .formatting import wrap_text as wrap_text
-from .globals import get_current_context as get_current_context
-from .parser import OptionParser as OptionParser
-from .termui import clear as clear
-from .termui import confirm as confirm
-from .termui import echo_via_pager as echo_via_pager
-from .termui import edit as edit
-from .termui import get_terminal_size as get_terminal_size
-from .termui import getchar as getchar
-from .termui import launch as launch
-from .termui import pause as pause
-from .termui import progressbar as progressbar
-from .termui import prompt as prompt
-from .termui import secho as secho
-from .termui import style as style
-from .termui import unstyle as unstyle
-from .types import BOOL as BOOL
-from .types import Choice as Choice
-from .types import DateTime as DateTime
-from .types import File as File
-from .types import FLOAT as FLOAT
-from .types import FloatRange as FloatRange
-from .types import INT as INT
-from .types import IntRange as IntRange
-from .types import ParamType as ParamType
-from .types import Path as Path
-from .types import STRING as STRING
-from .types import Tuple as Tuple
-from .types import UNPROCESSED as UNPROCESSED
-from .types import UUID as UUID
-from .utils import echo as echo
-from .utils import format_filename as format_filename
-from .utils import get_app_dir as get_app_dir
-from .utils import get_binary_stream as get_binary_stream
-from .utils import get_os_args as get_os_args
-from .utils import get_text_stream as get_text_stream
-from .utils import open_file as open_file
-
-__version__ = "8.0.1"
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/__init__.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/__init__.cpython-39.pyc
deleted file mode 100644
index 8ccd9fd..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/__init__.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/_compat.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/_compat.cpython-39.pyc
deleted file mode 100644
index 88c9cc5..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/_compat.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/_termui_impl.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/_termui_impl.cpython-39.pyc
deleted file mode 100644
index e843558..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/_termui_impl.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/_textwrap.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/_textwrap.cpython-39.pyc
deleted file mode 100644
index 3f9aa10..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/_textwrap.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/_unicodefun.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/_unicodefun.cpython-39.pyc
deleted file mode 100644
index c9cde52..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/_unicodefun.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/_winconsole.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/_winconsole.cpython-39.pyc
deleted file mode 100644
index 4373a24..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/_winconsole.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/core.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/core.cpython-39.pyc
deleted file mode 100644
index fcd753a..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/core.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/decorators.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/decorators.cpython-39.pyc
deleted file mode 100644
index 30e57a5..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/decorators.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/exceptions.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/exceptions.cpython-39.pyc
deleted file mode 100644
index 7cebd04..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/exceptions.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/formatting.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/formatting.cpython-39.pyc
deleted file mode 100644
index dcc28f2..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/formatting.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/globals.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/globals.cpython-39.pyc
deleted file mode 100644
index 6d658fd..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/globals.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/parser.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/parser.cpython-39.pyc
deleted file mode 100644
index 9136968..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/parser.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/shell_completion.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/shell_completion.cpython-39.pyc
deleted file mode 100644
index f97c219..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/shell_completion.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/termui.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/termui.cpython-39.pyc
deleted file mode 100644
index bbede3a..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/termui.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/testing.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/testing.cpython-39.pyc
deleted file mode 100644
index 040eb10..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/testing.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/types.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/types.cpython-39.pyc
deleted file mode 100644
index 50757a6..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/types.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/__pycache__/utils.cpython-39.pyc b/venv/lib/python3.9/site-packages/click/__pycache__/utils.cpython-39.pyc
deleted file mode 100644
index 20e2141..0000000
Binary files a/venv/lib/python3.9/site-packages/click/__pycache__/utils.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/click/_compat.py b/venv/lib/python3.9/site-packages/click/_compat.py
deleted file mode 100644
index b9e1f0d..0000000
--- a/venv/lib/python3.9/site-packages/click/_compat.py
+++ /dev/null
@@ -1,627 +0,0 @@
-import codecs
-import io
-import os
-import re
-import sys
-import typing as t
-from weakref import WeakKeyDictionary
-
-CYGWIN = sys.platform.startswith("cygwin")
-MSYS2 = sys.platform.startswith("win") and ("GCC" in sys.version)
-# Determine local App Engine environment, per Google's own suggestion
-APP_ENGINE = "APPENGINE_RUNTIME" in os.environ and "Development/" in os.environ.get(
- "SERVER_SOFTWARE", ""
-)
-WIN = sys.platform.startswith("win") and not APP_ENGINE and not MSYS2
-auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None
-_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]")
-
-
-def get_filesystem_encoding() -> str:
- return sys.getfilesystemencoding() or sys.getdefaultencoding()
-
-
-def _make_text_stream(
- stream: t.BinaryIO,
- encoding: t.Optional[str],
- errors: t.Optional[str],
- force_readable: bool = False,
- force_writable: bool = False,
-) -> t.TextIO:
- if encoding is None:
- encoding = get_best_encoding(stream)
- if errors is None:
- errors = "replace"
- return _NonClosingTextIOWrapper(
- stream,
- encoding,
- errors,
- line_buffering=True,
- force_readable=force_readable,
- force_writable=force_writable,
- )
-
-
-def is_ascii_encoding(encoding: str) -> bool:
- """Checks if a given encoding is ascii."""
- try:
- return codecs.lookup(encoding).name == "ascii"
- except LookupError:
- return False
-
-
-def get_best_encoding(stream: t.IO) -> str:
- """Returns the default stream encoding if not found."""
- rv = getattr(stream, "encoding", None) or sys.getdefaultencoding()
- if is_ascii_encoding(rv):
- return "utf-8"
- return rv
-
-
-class _NonClosingTextIOWrapper(io.TextIOWrapper):
- def __init__(
- self,
- stream: t.BinaryIO,
- encoding: t.Optional[str],
- errors: t.Optional[str],
- force_readable: bool = False,
- force_writable: bool = False,
- **extra: t.Any,
- ) -> None:
- self._stream = stream = t.cast(
- t.BinaryIO, _FixupStream(stream, force_readable, force_writable)
- )
- super().__init__(stream, encoding, errors, **extra)
-
- def __del__(self) -> None:
- try:
- self.detach()
- except Exception:
- pass
-
- def isatty(self) -> bool:
- # https://bitbucket.org/pypy/pypy/issue/1803
- return self._stream.isatty()
-
-
-class _FixupStream:
- """The new io interface needs more from streams than streams
- traditionally implement. As such, this fix-up code is necessary in
- some circumstances.
-
- The forcing of readable and writable flags are there because some tools
- put badly patched objects on sys (one such offender are certain version
- of jupyter notebook).
- """
-
- def __init__(
- self,
- stream: t.BinaryIO,
- force_readable: bool = False,
- force_writable: bool = False,
- ):
- self._stream = stream
- self._force_readable = force_readable
- self._force_writable = force_writable
-
- def __getattr__(self, name: str) -> t.Any:
- return getattr(self._stream, name)
-
- def read1(self, size: int) -> bytes:
- f = getattr(self._stream, "read1", None)
-
- if f is not None:
- return t.cast(bytes, f(size))
-
- return self._stream.read(size)
-
- def readable(self) -> bool:
- if self._force_readable:
- return True
- x = getattr(self._stream, "readable", None)
- if x is not None:
- return t.cast(bool, x())
- try:
- self._stream.read(0)
- except Exception:
- return False
- return True
-
- def writable(self) -> bool:
- if self._force_writable:
- return True
- x = getattr(self._stream, "writable", None)
- if x is not None:
- return t.cast(bool, x())
- try:
- self._stream.write("") # type: ignore
- except Exception:
- try:
- self._stream.write(b"")
- except Exception:
- return False
- return True
-
- def seekable(self) -> bool:
- x = getattr(self._stream, "seekable", None)
- if x is not None:
- return t.cast(bool, x())
- try:
- self._stream.seek(self._stream.tell())
- except Exception:
- return False
- return True
-
-
-def _is_binary_reader(stream: t.IO, default: bool = False) -> bool:
- try:
- return isinstance(stream.read(0), bytes)
- except Exception:
- return default
- # This happens in some cases where the stream was already
- # closed. In this case, we assume the default.
-
-
-def _is_binary_writer(stream: t.IO, default: bool = False) -> bool:
- try:
- stream.write(b"")
- except Exception:
- try:
- stream.write("")
- return False
- except Exception:
- pass
- return default
- return True
-
-
-def _find_binary_reader(stream: t.IO) -> t.Optional[t.BinaryIO]:
- # We need to figure out if the given stream is already binary.
- # This can happen because the official docs recommend detaching
- # the streams to get binary streams. Some code might do this, so
- # we need to deal with this case explicitly.
- if _is_binary_reader(stream, False):
- return t.cast(t.BinaryIO, stream)
-
- buf = getattr(stream, "buffer", None)
-
- # Same situation here; this time we assume that the buffer is
- # actually binary in case it's closed.
- if buf is not None and _is_binary_reader(buf, True):
- return t.cast(t.BinaryIO, buf)
-
- return None
-
-
-def _find_binary_writer(stream: t.IO) -> t.Optional[t.BinaryIO]:
- # We need to figure out if the given stream is already binary.
- # This can happen because the official docs recommend detaching
- # the streams to get binary streams. Some code might do this, so
- # we need to deal with this case explicitly.
- if _is_binary_writer(stream, False):
- return t.cast(t.BinaryIO, stream)
-
- buf = getattr(stream, "buffer", None)
-
- # Same situation here; this time we assume that the buffer is
- # actually binary in case it's closed.
- if buf is not None and _is_binary_writer(buf, True):
- return t.cast(t.BinaryIO, buf)
-
- return None
-
-
-def _stream_is_misconfigured(stream: t.TextIO) -> bool:
- """A stream is misconfigured if its encoding is ASCII."""
- # If the stream does not have an encoding set, we assume it's set
- # to ASCII. This appears to happen in certain unittest
- # environments. It's not quite clear what the correct behavior is
- # but this at least will force Click to recover somehow.
- return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii")
-
-
-def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool:
- """A stream attribute is compatible if it is equal to the
- desired value or the desired value is unset and the attribute
- has a value.
- """
- stream_value = getattr(stream, attr, None)
- return stream_value == value or (value is None and stream_value is not None)
-
-
-def _is_compatible_text_stream(
- stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str]
-) -> bool:
- """Check if a stream's encoding and errors attributes are
- compatible with the desired values.
- """
- return _is_compat_stream_attr(
- stream, "encoding", encoding
- ) and _is_compat_stream_attr(stream, "errors", errors)
-
-
-def _force_correct_text_stream(
- text_stream: t.IO,
- encoding: t.Optional[str],
- errors: t.Optional[str],
- is_binary: t.Callable[[t.IO, bool], bool],
- find_binary: t.Callable[[t.IO], t.Optional[t.BinaryIO]],
- force_readable: bool = False,
- force_writable: bool = False,
-) -> t.TextIO:
- if is_binary(text_stream, False):
- binary_reader = t.cast(t.BinaryIO, text_stream)
- else:
- text_stream = t.cast(t.TextIO, text_stream)
- # If the stream looks compatible, and won't default to a
- # misconfigured ascii encoding, return it as-is.
- if _is_compatible_text_stream(text_stream, encoding, errors) and not (
- encoding is None and _stream_is_misconfigured(text_stream)
- ):
- return text_stream
-
- # Otherwise, get the underlying binary reader.
- possible_binary_reader = find_binary(text_stream)
-
- # If that's not possible, silently use the original reader
- # and get mojibake instead of exceptions.
- if possible_binary_reader is None:
- return text_stream
-
- binary_reader = possible_binary_reader
-
- # Default errors to replace instead of strict in order to get
- # something that works.
- if errors is None:
- errors = "replace"
-
- # Wrap the binary stream in a text stream with the correct
- # encoding parameters.
- return _make_text_stream(
- binary_reader,
- encoding,
- errors,
- force_readable=force_readable,
- force_writable=force_writable,
- )
-
-
-def _force_correct_text_reader(
- text_reader: t.IO,
- encoding: t.Optional[str],
- errors: t.Optional[str],
- force_readable: bool = False,
-) -> t.TextIO:
- return _force_correct_text_stream(
- text_reader,
- encoding,
- errors,
- _is_binary_reader,
- _find_binary_reader,
- force_readable=force_readable,
- )
-
-
-def _force_correct_text_writer(
- text_writer: t.IO,
- encoding: t.Optional[str],
- errors: t.Optional[str],
- force_writable: bool = False,
-) -> t.TextIO:
- return _force_correct_text_stream(
- text_writer,
- encoding,
- errors,
- _is_binary_writer,
- _find_binary_writer,
- force_writable=force_writable,
- )
-
-
-def get_binary_stdin() -> t.BinaryIO:
- reader = _find_binary_reader(sys.stdin)
- if reader is None:
- raise RuntimeError("Was not able to determine binary stream for sys.stdin.")
- return reader
-
-
-def get_binary_stdout() -> t.BinaryIO:
- writer = _find_binary_writer(sys.stdout)
- if writer is None:
- raise RuntimeError("Was not able to determine binary stream for sys.stdout.")
- return writer
-
-
-def get_binary_stderr() -> t.BinaryIO:
- writer = _find_binary_writer(sys.stderr)
- if writer is None:
- raise RuntimeError("Was not able to determine binary stream for sys.stderr.")
- return writer
-
-
-def get_text_stdin(
- encoding: t.Optional[str] = None, errors: t.Optional[str] = None
-) -> t.TextIO:
- rv = _get_windows_console_stream(sys.stdin, encoding, errors)
- if rv is not None:
- return rv
- return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True)
-
-
-def get_text_stdout(
- encoding: t.Optional[str] = None, errors: t.Optional[str] = None
-) -> t.TextIO:
- rv = _get_windows_console_stream(sys.stdout, encoding, errors)
- if rv is not None:
- return rv
- return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True)
-
-
-def get_text_stderr(
- encoding: t.Optional[str] = None, errors: t.Optional[str] = None
-) -> t.TextIO:
- rv = _get_windows_console_stream(sys.stderr, encoding, errors)
- if rv is not None:
- return rv
- return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True)
-
-
-def _wrap_io_open(
- file: t.Union[str, os.PathLike, int],
- mode: str,
- encoding: t.Optional[str],
- errors: t.Optional[str],
-) -> t.IO:
- """Handles not passing ``encoding`` and ``errors`` in binary mode."""
- if "b" in mode:
- return open(file, mode)
-
- return open(file, mode, encoding=encoding, errors=errors)
-
-
-def open_stream(
- filename: str,
- mode: str = "r",
- encoding: t.Optional[str] = None,
- errors: t.Optional[str] = "strict",
- atomic: bool = False,
-) -> t.Tuple[t.IO, bool]:
- binary = "b" in mode
-
- # Standard streams first. These are simple because they don't need
- # special handling for the atomic flag. It's entirely ignored.
- if filename == "-":
- if any(m in mode for m in ["w", "a", "x"]):
- if binary:
- return get_binary_stdout(), False
- return get_text_stdout(encoding=encoding, errors=errors), False
- if binary:
- return get_binary_stdin(), False
- return get_text_stdin(encoding=encoding, errors=errors), False
-
- # Non-atomic writes directly go out through the regular open functions.
- if not atomic:
- return _wrap_io_open(filename, mode, encoding, errors), True
-
- # Some usability stuff for atomic writes
- if "a" in mode:
- raise ValueError(
- "Appending to an existing file is not supported, because that"
- " would involve an expensive `copy`-operation to a temporary"
- " file. Open the file in normal `w`-mode and copy explicitly"
- " if that's what you're after."
- )
- if "x" in mode:
- raise ValueError("Use the `overwrite`-parameter instead.")
- if "w" not in mode:
- raise ValueError("Atomic writes only make sense with `w`-mode.")
-
- # Atomic writes are more complicated. They work by opening a file
- # as a proxy in the same folder and then using the fdopen
- # functionality to wrap it in a Python file. Then we wrap it in an
- # atomic file that moves the file over on close.
- import errno
- import random
-
- try:
- perm: t.Optional[int] = os.stat(filename).st_mode
- except OSError:
- perm = None
-
- flags = os.O_RDWR | os.O_CREAT | os.O_EXCL
-
- if binary:
- flags |= getattr(os, "O_BINARY", 0)
-
- while True:
- tmp_filename = os.path.join(
- os.path.dirname(filename),
- f".__atomic-write{random.randrange(1 << 32):08x}",
- )
- try:
- fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm)
- break
- except OSError as e:
- if e.errno == errno.EEXIST or (
- os.name == "nt"
- and e.errno == errno.EACCES
- and os.path.isdir(e.filename)
- and os.access(e.filename, os.W_OK)
- ):
- continue
- raise
-
- if perm is not None:
- os.chmod(tmp_filename, perm) # in case perm includes bits in umask
-
- f = _wrap_io_open(fd, mode, encoding, errors)
- af = _AtomicFile(f, tmp_filename, os.path.realpath(filename))
- return t.cast(t.IO, af), True
-
-
-class _AtomicFile:
- def __init__(self, f: t.IO, tmp_filename: str, real_filename: str) -> None:
- self._f = f
- self._tmp_filename = tmp_filename
- self._real_filename = real_filename
- self.closed = False
-
- @property
- def name(self) -> str:
- return self._real_filename
-
- def close(self, delete: bool = False) -> None:
- if self.closed:
- return
- self._f.close()
- os.replace(self._tmp_filename, self._real_filename)
- self.closed = True
-
- def __getattr__(self, name: str) -> t.Any:
- return getattr(self._f, name)
-
- def __enter__(self) -> "_AtomicFile":
- return self
-
- def __exit__(self, exc_type, exc_value, tb): # type: ignore
- self.close(delete=exc_type is not None)
-
- def __repr__(self) -> str:
- return repr(self._f)
-
-
-def strip_ansi(value: str) -> str:
- return _ansi_re.sub("", value)
-
-
-def _is_jupyter_kernel_output(stream: t.IO) -> bool:
- while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)):
- stream = stream._stream
-
- return stream.__class__.__module__.startswith("ipykernel.")
-
-
-def should_strip_ansi(
- stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None
-) -> bool:
- if color is None:
- if stream is None:
- stream = sys.stdin
- return not isatty(stream) and not _is_jupyter_kernel_output(stream)
- return not color
-
-
-# On Windows, wrap the output streams with colorama to support ANSI
-# color codes.
-# NOTE: double check is needed so mypy does not analyze this on Linux
-if sys.platform.startswith("win") and WIN:
- from ._winconsole import _get_windows_console_stream
-
- def _get_argv_encoding() -> str:
- import locale
-
- return locale.getpreferredencoding()
-
- _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary()
-
- def auto_wrap_for_ansi(
- stream: t.TextIO, color: t.Optional[bool] = None
- ) -> t.TextIO:
- """Support ANSI color and style codes on Windows by wrapping a
- stream with colorama.
- """
- try:
- cached = _ansi_stream_wrappers.get(stream)
- except Exception:
- cached = None
-
- if cached is not None:
- return cached
-
- import colorama
-
- strip = should_strip_ansi(stream, color)
- ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip)
- rv = t.cast(t.TextIO, ansi_wrapper.stream)
- _write = rv.write
-
- def _safe_write(s):
- try:
- return _write(s)
- except BaseException:
- ansi_wrapper.reset_all()
- raise
-
- rv.write = _safe_write
-
- try:
- _ansi_stream_wrappers[stream] = rv
- except Exception:
- pass
-
- return rv
-
-
-else:
-
- def _get_argv_encoding() -> str:
- return getattr(sys.stdin, "encoding", None) or get_filesystem_encoding()
-
- def _get_windows_console_stream(
- f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str]
- ) -> t.Optional[t.TextIO]:
- return None
-
-
-def term_len(x: str) -> int:
- return len(strip_ansi(x))
-
-
-def isatty(stream: t.IO) -> bool:
- try:
- return stream.isatty()
- except Exception:
- return False
-
-
-def _make_cached_stream_func(
- src_func: t.Callable[[], t.TextIO], wrapper_func: t.Callable[[], t.TextIO]
-) -> t.Callable[[], t.TextIO]:
- cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary()
-
- def func() -> t.TextIO:
- stream = src_func()
- try:
- rv = cache.get(stream)
- except Exception:
- rv = None
- if rv is not None:
- return rv
- rv = wrapper_func()
- try:
- cache[stream] = rv
- except Exception:
- pass
- return rv
-
- return func
-
-
-_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin)
-_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout)
-_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr)
-
-
-binary_streams: t.Mapping[str, t.Callable[[], t.BinaryIO]] = {
- "stdin": get_binary_stdin,
- "stdout": get_binary_stdout,
- "stderr": get_binary_stderr,
-}
-
-text_streams: t.Mapping[
- str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO]
-] = {
- "stdin": get_text_stdin,
- "stdout": get_text_stdout,
- "stderr": get_text_stderr,
-}
diff --git a/venv/lib/python3.9/site-packages/click/_termui_impl.py b/venv/lib/python3.9/site-packages/click/_termui_impl.py
deleted file mode 100644
index 06cf2b7..0000000
--- a/venv/lib/python3.9/site-packages/click/_termui_impl.py
+++ /dev/null
@@ -1,717 +0,0 @@
-"""
-This module contains implementations for the termui module. To keep the
-import time of Click down, some infrequently used functionality is
-placed in this module and only imported as needed.
-"""
-import contextlib
-import math
-import os
-import sys
-import time
-import typing as t
-from gettext import gettext as _
-
-from ._compat import _default_text_stdout
-from ._compat import CYGWIN
-from ._compat import get_best_encoding
-from ._compat import isatty
-from ._compat import open_stream
-from ._compat import strip_ansi
-from ._compat import term_len
-from ._compat import WIN
-from .exceptions import ClickException
-from .utils import echo
-
-V = t.TypeVar("V")
-
-if os.name == "nt":
- BEFORE_BAR = "\r"
- AFTER_BAR = "\n"
-else:
- BEFORE_BAR = "\r\033[?25l"
- AFTER_BAR = "\033[?25h\n"
-
-
-class ProgressBar(t.Generic[V]):
- def __init__(
- self,
- iterable: t.Optional[t.Iterable[V]],
- length: t.Optional[int] = None,
- fill_char: str = "#",
- empty_char: str = " ",
- bar_template: str = "%(bar)s",
- info_sep: str = " ",
- show_eta: bool = True,
- show_percent: t.Optional[bool] = None,
- show_pos: bool = False,
- item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None,
- label: t.Optional[str] = None,
- file: t.Optional[t.TextIO] = None,
- color: t.Optional[bool] = None,
- update_min_steps: int = 1,
- width: int = 30,
- ) -> None:
- self.fill_char = fill_char
- self.empty_char = empty_char
- self.bar_template = bar_template
- self.info_sep = info_sep
- self.show_eta = show_eta
- self.show_percent = show_percent
- self.show_pos = show_pos
- self.item_show_func = item_show_func
- self.label = label or ""
- if file is None:
- file = _default_text_stdout()
- self.file = file
- self.color = color
- self.update_min_steps = update_min_steps
- self._completed_intervals = 0
- self.width = width
- self.autowidth = width == 0
-
- if length is None:
- from operator import length_hint
-
- length = length_hint(iterable, -1)
-
- if length == -1:
- length = None
- if iterable is None:
- if length is None:
- raise TypeError("iterable or length is required")
- iterable = t.cast(t.Iterable[V], range(length))
- self.iter = iter(iterable)
- self.length = length
- self.pos = 0
- self.avg: t.List[float] = []
- self.start = self.last_eta = time.time()
- self.eta_known = False
- self.finished = False
- self.max_width: t.Optional[int] = None
- self.entered = False
- self.current_item: t.Optional[V] = None
- self.is_hidden = not isatty(self.file)
- self._last_line: t.Optional[str] = None
-
- def __enter__(self) -> "ProgressBar":
- self.entered = True
- self.render_progress()
- return self
-
- def __exit__(self, exc_type, exc_value, tb): # type: ignore
- self.render_finish()
-
- def __iter__(self) -> t.Iterator[V]:
- if not self.entered:
- raise RuntimeError("You need to use progress bars in a with block.")
- self.render_progress()
- return self.generator()
-
- def __next__(self) -> V:
- # Iteration is defined in terms of a generator function,
- # returned by iter(self); use that to define next(). This works
- # because `self.iter` is an iterable consumed by that generator,
- # so it is re-entry safe. Calling `next(self.generator())`
- # twice works and does "what you want".
- return next(iter(self))
-
- def render_finish(self) -> None:
- if self.is_hidden:
- return
- self.file.write(AFTER_BAR)
- self.file.flush()
-
- @property
- def pct(self) -> float:
- if self.finished:
- return 1.0
- return min(self.pos / (float(self.length or 1) or 1), 1.0)
-
- @property
- def time_per_iteration(self) -> float:
- if not self.avg:
- return 0.0
- return sum(self.avg) / float(len(self.avg))
-
- @property
- def eta(self) -> float:
- if self.length is not None and not self.finished:
- return self.time_per_iteration * (self.length - self.pos)
- return 0.0
-
- def format_eta(self) -> str:
- if self.eta_known:
- t = int(self.eta)
- seconds = t % 60
- t //= 60
- minutes = t % 60
- t //= 60
- hours = t % 24
- t //= 24
- if t > 0:
- return f"{t}d {hours:02}:{minutes:02}:{seconds:02}"
- else:
- return f"{hours:02}:{minutes:02}:{seconds:02}"
- return ""
-
- def format_pos(self) -> str:
- pos = str(self.pos)
- if self.length is not None:
- pos += f"/{self.length}"
- return pos
-
- def format_pct(self) -> str:
- return f"{int(self.pct * 100): 4}%"[1:]
-
- def format_bar(self) -> str:
- if self.length is not None:
- bar_length = int(self.pct * self.width)
- bar = self.fill_char * bar_length
- bar += self.empty_char * (self.width - bar_length)
- elif self.finished:
- bar = self.fill_char * self.width
- else:
- chars = list(self.empty_char * (self.width or 1))
- if self.time_per_iteration != 0:
- chars[
- int(
- (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5)
- * self.width
- )
- ] = self.fill_char
- bar = "".join(chars)
- return bar
-
- def format_progress_line(self) -> str:
- show_percent = self.show_percent
-
- info_bits = []
- if self.length is not None and show_percent is None:
- show_percent = not self.show_pos
-
- if self.show_pos:
- info_bits.append(self.format_pos())
- if show_percent:
- info_bits.append(self.format_pct())
- if self.show_eta and self.eta_known and not self.finished:
- info_bits.append(self.format_eta())
- if self.item_show_func is not None:
- item_info = self.item_show_func(self.current_item)
- if item_info is not None:
- info_bits.append(item_info)
-
- return (
- self.bar_template
- % {
- "label": self.label,
- "bar": self.format_bar(),
- "info": self.info_sep.join(info_bits),
- }
- ).rstrip()
-
- def render_progress(self) -> None:
- import shutil
-
- if self.is_hidden:
- # Only output the label as it changes if the output is not a
- # TTY. Use file=stderr if you expect to be piping stdout.
- if self._last_line != self.label:
- self._last_line = self.label
- echo(self.label, file=self.file, color=self.color)
-
- return
-
- buf = []
- # Update width in case the terminal has been resized
- if self.autowidth:
- old_width = self.width
- self.width = 0
- clutter_length = term_len(self.format_progress_line())
- new_width = max(0, shutil.get_terminal_size().columns - clutter_length)
- if new_width < old_width:
- buf.append(BEFORE_BAR)
- buf.append(" " * self.max_width) # type: ignore
- self.max_width = new_width
- self.width = new_width
-
- clear_width = self.width
- if self.max_width is not None:
- clear_width = self.max_width
-
- buf.append(BEFORE_BAR)
- line = self.format_progress_line()
- line_len = term_len(line)
- if self.max_width is None or self.max_width < line_len:
- self.max_width = line_len
-
- buf.append(line)
- buf.append(" " * (clear_width - line_len))
- line = "".join(buf)
- # Render the line only if it changed.
-
- if line != self._last_line:
- self._last_line = line
- echo(line, file=self.file, color=self.color, nl=False)
- self.file.flush()
-
- def make_step(self, n_steps: int) -> None:
- self.pos += n_steps
- if self.length is not None and self.pos >= self.length:
- self.finished = True
-
- if (time.time() - self.last_eta) < 1.0:
- return
-
- self.last_eta = time.time()
-
- # self.avg is a rolling list of length <= 7 of steps where steps are
- # defined as time elapsed divided by the total progress through
- # self.length.
- if self.pos:
- step = (time.time() - self.start) / self.pos
- else:
- step = time.time() - self.start
-
- self.avg = self.avg[-6:] + [step]
-
- self.eta_known = self.length is not None
-
- def update(self, n_steps: int, current_item: t.Optional[V] = None) -> None:
- """Update the progress bar by advancing a specified number of
- steps, and optionally set the ``current_item`` for this new
- position.
-
- :param n_steps: Number of steps to advance.
- :param current_item: Optional item to set as ``current_item``
- for the updated position.
-
- .. versionchanged:: 8.0
- Added the ``current_item`` optional parameter.
-
- .. versionchanged:: 8.0
- Only render when the number of steps meets the
- ``update_min_steps`` threshold.
- """
- if current_item is not None:
- self.current_item = current_item
-
- self._completed_intervals += n_steps
-
- if self._completed_intervals >= self.update_min_steps:
- self.make_step(self._completed_intervals)
- self.render_progress()
- self._completed_intervals = 0
-
- def finish(self) -> None:
- self.eta_known = False
- self.current_item = None
- self.finished = True
-
- def generator(self) -> t.Iterator[V]:
- """Return a generator which yields the items added to the bar
- during construction, and updates the progress bar *after* the
- yielded block returns.
- """
- # WARNING: the iterator interface for `ProgressBar` relies on
- # this and only works because this is a simple generator which
- # doesn't create or manage additional state. If this function
- # changes, the impact should be evaluated both against
- # `iter(bar)` and `next(bar)`. `next()` in particular may call
- # `self.generator()` repeatedly, and this must remain safe in
- # order for that interface to work.
- if not self.entered:
- raise RuntimeError("You need to use progress bars in a with block.")
-
- if self.is_hidden:
- yield from self.iter
- else:
- for rv in self.iter:
- self.current_item = rv
-
- # This allows show_item_func to be updated before the
- # item is processed. Only trigger at the beginning of
- # the update interval.
- if self._completed_intervals == 0:
- self.render_progress()
-
- yield rv
- self.update(1)
-
- self.finish()
- self.render_progress()
-
-
-def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None:
- """Decide what method to use for paging through text."""
- stdout = _default_text_stdout()
- if not isatty(sys.stdin) or not isatty(stdout):
- return _nullpager(stdout, generator, color)
- pager_cmd = (os.environ.get("PAGER", None) or "").strip()
- if pager_cmd:
- if WIN:
- return _tempfilepager(generator, pager_cmd, color)
- return _pipepager(generator, pager_cmd, color)
- if os.environ.get("TERM") in ("dumb", "emacs"):
- return _nullpager(stdout, generator, color)
- if WIN or sys.platform.startswith("os2"):
- return _tempfilepager(generator, "more <", color)
- if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0:
- return _pipepager(generator, "less", color)
-
- import tempfile
-
- fd, filename = tempfile.mkstemp()
- os.close(fd)
- try:
- if hasattr(os, "system") and os.system(f'more "{filename}"') == 0:
- return _pipepager(generator, "more", color)
- return _nullpager(stdout, generator, color)
- finally:
- os.unlink(filename)
-
-
-def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> None:
- """Page through text by feeding it to another program. Invoking a
- pager through this might support colors.
- """
- import subprocess
-
- env = dict(os.environ)
-
- # If we're piping to less we might support colors under the
- # condition that
- cmd_detail = cmd.rsplit("/", 1)[-1].split()
- if color is None and cmd_detail[0] == "less":
- less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}"
- if not less_flags:
- env["LESS"] = "-R"
- color = True
- elif "r" in less_flags or "R" in less_flags:
- color = True
-
- c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, env=env)
- stdin = t.cast(t.BinaryIO, c.stdin)
- encoding = get_best_encoding(stdin)
- try:
- for text in generator:
- if not color:
- text = strip_ansi(text)
-
- stdin.write(text.encode(encoding, "replace"))
- except (OSError, KeyboardInterrupt):
- pass
- else:
- stdin.close()
-
- # Less doesn't respect ^C, but catches it for its own UI purposes (aborting
- # search or other commands inside less).
- #
- # That means when the user hits ^C, the parent process (click) terminates,
- # but less is still alive, paging the output and messing up the terminal.
- #
- # If the user wants to make the pager exit on ^C, they should set
- # `LESS='-K'`. It's not our decision to make.
- while True:
- try:
- c.wait()
- except KeyboardInterrupt:
- pass
- else:
- break
-
-
-def _tempfilepager(
- generator: t.Iterable[str], cmd: str, color: t.Optional[bool]
-) -> None:
- """Page through text by invoking a program on a temporary file."""
- import tempfile
-
- _, filename = tempfile.mkstemp()
- # TODO: This never terminates if the passed generator never terminates.
- text = "".join(generator)
- if not color:
- text = strip_ansi(text)
- encoding = get_best_encoding(sys.stdout)
- with open_stream(filename, "wb")[0] as f:
- f.write(text.encode(encoding))
- try:
- os.system(f'{cmd} "{filename}"')
- finally:
- os.unlink(filename)
-
-
-def _nullpager(
- stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool]
-) -> None:
- """Simply print unformatted text. This is the ultimate fallback."""
- for text in generator:
- if not color:
- text = strip_ansi(text)
- stream.write(text)
-
-
-class Editor:
- def __init__(
- self,
- editor: t.Optional[str] = None,
- env: t.Optional[t.Mapping[str, str]] = None,
- require_save: bool = True,
- extension: str = ".txt",
- ) -> None:
- self.editor = editor
- self.env = env
- self.require_save = require_save
- self.extension = extension
-
- def get_editor(self) -> str:
- if self.editor is not None:
- return self.editor
- for key in "VISUAL", "EDITOR":
- rv = os.environ.get(key)
- if rv:
- return rv
- if WIN:
- return "notepad"
- for editor in "sensible-editor", "vim", "nano":
- if os.system(f"which {editor} >/dev/null 2>&1") == 0:
- return editor
- return "vi"
-
- def edit_file(self, filename: str) -> None:
- import subprocess
-
- editor = self.get_editor()
- environ: t.Optional[t.Dict[str, str]] = None
-
- if self.env:
- environ = os.environ.copy()
- environ.update(self.env)
-
- try:
- c = subprocess.Popen(f'{editor} "{filename}"', env=environ, shell=True)
- exit_code = c.wait()
- if exit_code != 0:
- raise ClickException(
- _("{editor}: Editing failed").format(editor=editor)
- )
- except OSError as e:
- raise ClickException(
- _("{editor}: Editing failed: {e}").format(editor=editor, e=e)
- )
-
- def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]:
- import tempfile
-
- if not text:
- data = b""
- elif isinstance(text, (bytes, bytearray)):
- data = text
- else:
- if text and not text.endswith("\n"):
- text += "\n"
-
- if WIN:
- data = text.replace("\n", "\r\n").encode("utf-8-sig")
- else:
- data = text.encode("utf-8")
-
- fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension)
- f: t.BinaryIO
-
- try:
- with os.fdopen(fd, "wb") as f:
- f.write(data)
-
- # If the filesystem resolution is 1 second, like Mac OS
- # 10.12 Extended, or 2 seconds, like FAT32, and the editor
- # closes very fast, require_save can fail. Set the modified
- # time to be 2 seconds in the past to work around this.
- os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2))
- # Depending on the resolution, the exact value might not be
- # recorded, so get the new recorded value.
- timestamp = os.path.getmtime(name)
-
- self.edit_file(name)
-
- if self.require_save and os.path.getmtime(name) == timestamp:
- return None
-
- with open(name, "rb") as f:
- rv = f.read()
-
- if isinstance(text, (bytes, bytearray)):
- return rv
-
- return rv.decode("utf-8-sig").replace("\r\n", "\n") # type: ignore
- finally:
- os.unlink(name)
-
-
-def open_url(url: str, wait: bool = False, locate: bool = False) -> int:
- import subprocess
-
- def _unquote_file(url: str) -> str:
- from urllib.parse import unquote
-
- if url.startswith("file://"):
- url = unquote(url[7:])
-
- return url
-
- if sys.platform == "darwin":
- args = ["open"]
- if wait:
- args.append("-W")
- if locate:
- args.append("-R")
- args.append(_unquote_file(url))
- null = open("/dev/null", "w")
- try:
- return subprocess.Popen(args, stderr=null).wait()
- finally:
- null.close()
- elif WIN:
- if locate:
- url = _unquote_file(url.replace('"', ""))
- args = f'explorer /select,"{url}"'
- else:
- url = url.replace('"', "")
- wait_str = "/WAIT" if wait else ""
- args = f'start {wait_str} "" "{url}"'
- return os.system(args)
- elif CYGWIN:
- if locate:
- url = os.path.dirname(_unquote_file(url).replace('"', ""))
- args = f'cygstart "{url}"'
- else:
- url = url.replace('"', "")
- wait_str = "-w" if wait else ""
- args = f'cygstart {wait_str} "{url}"'
- return os.system(args)
-
- try:
- if locate:
- url = os.path.dirname(_unquote_file(url)) or "."
- else:
- url = _unquote_file(url)
- c = subprocess.Popen(["xdg-open", url])
- if wait:
- return c.wait()
- return 0
- except OSError:
- if url.startswith(("http://", "https://")) and not locate and not wait:
- import webbrowser
-
- webbrowser.open(url)
- return 0
- return 1
-
-
-def _translate_ch_to_exc(ch: str) -> t.Optional[BaseException]:
- if ch == "\x03":
- raise KeyboardInterrupt()
-
- if ch == "\x04" and not WIN: # Unix-like, Ctrl+D
- raise EOFError()
-
- if ch == "\x1a" and WIN: # Windows, Ctrl+Z
- raise EOFError()
-
- return None
-
-
-if WIN:
- import msvcrt
-
- @contextlib.contextmanager
- def raw_terminal() -> t.Iterator[int]:
- yield -1
-
- def getchar(echo: bool) -> str:
- # The function `getch` will return a bytes object corresponding to
- # the pressed character. Since Windows 10 build 1803, it will also
- # return \x00 when called a second time after pressing a regular key.
- #
- # `getwch` does not share this probably-bugged behavior. Moreover, it
- # returns a Unicode object by default, which is what we want.
- #
- # Either of these functions will return \x00 or \xe0 to indicate
- # a special key, and you need to call the same function again to get
- # the "rest" of the code. The fun part is that \u00e0 is
- # "latin small letter a with grave", so if you type that on a French
- # keyboard, you _also_ get a \xe0.
- # E.g., consider the Up arrow. This returns \xe0 and then \x48. The
- # resulting Unicode string reads as "a with grave" + "capital H".
- # This is indistinguishable from when the user actually types
- # "a with grave" and then "capital H".
- #
- # When \xe0 is returned, we assume it's part of a special-key sequence
- # and call `getwch` again, but that means that when the user types
- # the \u00e0 character, `getchar` doesn't return until a second
- # character is typed.
- # The alternative is returning immediately, but that would mess up
- # cross-platform handling of arrow keys and others that start with
- # \xe0. Another option is using `getch`, but then we can't reliably
- # read non-ASCII characters, because return values of `getch` are
- # limited to the current 8-bit codepage.
- #
- # Anyway, Click doesn't claim to do this Right(tm), and using `getwch`
- # is doing the right thing in more situations than with `getch`.
- func: t.Callable[[], str]
-
- if echo:
- func = msvcrt.getwche # type: ignore
- else:
- func = msvcrt.getwch # type: ignore
-
- rv = func()
-
- if rv in ("\x00", "\xe0"):
- # \x00 and \xe0 are control characters that indicate special key,
- # see above.
- rv += func()
-
- _translate_ch_to_exc(rv)
- return rv
-
-
-else:
- import tty
- import termios
-
- @contextlib.contextmanager
- def raw_terminal() -> t.Iterator[int]:
- f: t.Optional[t.TextIO]
- fd: int
-
- if not isatty(sys.stdin):
- f = open("/dev/tty")
- fd = f.fileno()
- else:
- fd = sys.stdin.fileno()
- f = None
-
- try:
- old_settings = termios.tcgetattr(fd)
-
- try:
- tty.setraw(fd)
- yield fd
- finally:
- termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
- sys.stdout.flush()
-
- if f is not None:
- f.close()
- except termios.error:
- pass
-
- def getchar(echo: bool) -> str:
- with raw_terminal() as fd:
- ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace")
-
- if echo and isatty(sys.stdout):
- sys.stdout.write(ch)
-
- _translate_ch_to_exc(ch)
- return ch
diff --git a/venv/lib/python3.9/site-packages/click/_textwrap.py b/venv/lib/python3.9/site-packages/click/_textwrap.py
deleted file mode 100644
index b47dcbd..0000000
--- a/venv/lib/python3.9/site-packages/click/_textwrap.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import textwrap
-import typing as t
-from contextlib import contextmanager
-
-
-class TextWrapper(textwrap.TextWrapper):
- def _handle_long_word(
- self,
- reversed_chunks: t.List[str],
- cur_line: t.List[str],
- cur_len: int,
- width: int,
- ) -> None:
- space_left = max(width - cur_len, 1)
-
- if self.break_long_words:
- last = reversed_chunks[-1]
- cut = last[:space_left]
- res = last[space_left:]
- cur_line.append(cut)
- reversed_chunks[-1] = res
- elif not cur_line:
- cur_line.append(reversed_chunks.pop())
-
- @contextmanager
- def extra_indent(self, indent: str) -> t.Iterator[None]:
- old_initial_indent = self.initial_indent
- old_subsequent_indent = self.subsequent_indent
- self.initial_indent += indent
- self.subsequent_indent += indent
-
- try:
- yield
- finally:
- self.initial_indent = old_initial_indent
- self.subsequent_indent = old_subsequent_indent
-
- def indent_only(self, text: str) -> str:
- rv = []
-
- for idx, line in enumerate(text.splitlines()):
- indent = self.initial_indent
-
- if idx > 0:
- indent = self.subsequent_indent
-
- rv.append(f"{indent}{line}")
-
- return "\n".join(rv)
diff --git a/venv/lib/python3.9/site-packages/click/_unicodefun.py b/venv/lib/python3.9/site-packages/click/_unicodefun.py
deleted file mode 100644
index 9cb30c3..0000000
--- a/venv/lib/python3.9/site-packages/click/_unicodefun.py
+++ /dev/null
@@ -1,100 +0,0 @@
-import codecs
-import os
-from gettext import gettext as _
-
-
-def _verify_python_env() -> None:
- """Ensures that the environment is good for Unicode."""
- try:
- from locale import getpreferredencoding
-
- fs_enc = codecs.lookup(getpreferredencoding()).name
- except Exception:
- fs_enc = "ascii"
-
- if fs_enc != "ascii":
- return
-
- extra = [
- _(
- "Click will abort further execution because Python was"
- " configured to use ASCII as encoding for the environment."
- " Consult https://click.palletsprojects.com/unicode-support/"
- " for mitigation steps."
- )
- ]
-
- if os.name == "posix":
- import subprocess
-
- try:
- rv = subprocess.Popen(
- ["locale", "-a"],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- encoding="ascii",
- errors="replace",
- ).communicate()[0]
- except OSError:
- rv = ""
-
- good_locales = set()
- has_c_utf8 = False
-
- for line in rv.splitlines():
- locale = line.strip()
-
- if locale.lower().endswith((".utf-8", ".utf8")):
- good_locales.add(locale)
-
- if locale.lower() in ("c.utf8", "c.utf-8"):
- has_c_utf8 = True
-
- if not good_locales:
- extra.append(
- _(
- "Additional information: on this system no suitable"
- " UTF-8 locales were discovered. This most likely"
- " requires resolving by reconfiguring the locale"
- " system."
- )
- )
- elif has_c_utf8:
- extra.append(
- _(
- "This system supports the C.UTF-8 locale which is"
- " recommended. You might be able to resolve your"
- " issue by exporting the following environment"
- " variables:"
- )
- )
- extra.append(" export LC_ALL=C.UTF-8\n export LANG=C.UTF-8")
- else:
- extra.append(
- _(
- "This system lists some UTF-8 supporting locales"
- " that you can pick from. The following suitable"
- " locales were discovered: {locales}"
- ).format(locales=", ".join(sorted(good_locales)))
- )
-
- bad_locale = None
-
- for env_locale in os.environ.get("LC_ALL"), os.environ.get("LANG"):
- if env_locale and env_locale.lower().endswith((".utf-8", ".utf8")):
- bad_locale = env_locale
-
- if env_locale is not None:
- break
-
- if bad_locale is not None:
- extra.append(
- _(
- "Click discovered that you exported a UTF-8 locale"
- " but the locale system could not pick up from it"
- " because it does not exist. The exported locale is"
- " {locale!r} but it is not supported."
- ).format(locale=bad_locale)
- )
-
- raise RuntimeError("\n\n".join(extra))
diff --git a/venv/lib/python3.9/site-packages/click/_winconsole.py b/venv/lib/python3.9/site-packages/click/_winconsole.py
deleted file mode 100644
index 6b20df3..0000000
--- a/venv/lib/python3.9/site-packages/click/_winconsole.py
+++ /dev/null
@@ -1,279 +0,0 @@
-# This module is based on the excellent work by Adam Bartoš who
-# provided a lot of what went into the implementation here in
-# the discussion to issue1602 in the Python bug tracker.
-#
-# There are some general differences in regards to how this works
-# compared to the original patches as we do not need to patch
-# the entire interpreter but just work in our little world of
-# echo and prompt.
-import io
-import sys
-import time
-import typing as t
-from ctypes import byref
-from ctypes import c_char
-from ctypes import c_char_p
-from ctypes import c_int
-from ctypes import c_ssize_t
-from ctypes import c_ulong
-from ctypes import c_void_p
-from ctypes import POINTER
-from ctypes import py_object
-from ctypes import Structure
-from ctypes.wintypes import DWORD
-from ctypes.wintypes import HANDLE
-from ctypes.wintypes import LPCWSTR
-from ctypes.wintypes import LPWSTR
-
-from ._compat import _NonClosingTextIOWrapper
-
-assert sys.platform == "win32"
-import msvcrt # noqa: E402
-from ctypes import windll # noqa: E402
-from ctypes import WINFUNCTYPE # noqa: E402
-
-c_ssize_p = POINTER(c_ssize_t)
-
-kernel32 = windll.kernel32
-GetStdHandle = kernel32.GetStdHandle
-ReadConsoleW = kernel32.ReadConsoleW
-WriteConsoleW = kernel32.WriteConsoleW
-GetConsoleMode = kernel32.GetConsoleMode
-GetLastError = kernel32.GetLastError
-GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32))
-CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(
- ("CommandLineToArgvW", windll.shell32)
-)
-LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32))
-
-STDIN_HANDLE = GetStdHandle(-10)
-STDOUT_HANDLE = GetStdHandle(-11)
-STDERR_HANDLE = GetStdHandle(-12)
-
-PyBUF_SIMPLE = 0
-PyBUF_WRITABLE = 1
-
-ERROR_SUCCESS = 0
-ERROR_NOT_ENOUGH_MEMORY = 8
-ERROR_OPERATION_ABORTED = 995
-
-STDIN_FILENO = 0
-STDOUT_FILENO = 1
-STDERR_FILENO = 2
-
-EOF = b"\x1a"
-MAX_BYTES_WRITTEN = 32767
-
-try:
- from ctypes import pythonapi
-except ImportError:
- # On PyPy we cannot get buffers so our ability to operate here is
- # severely limited.
- get_buffer = None
-else:
-
- class Py_buffer(Structure):
- _fields_ = [
- ("buf", c_void_p),
- ("obj", py_object),
- ("len", c_ssize_t),
- ("itemsize", c_ssize_t),
- ("readonly", c_int),
- ("ndim", c_int),
- ("format", c_char_p),
- ("shape", c_ssize_p),
- ("strides", c_ssize_p),
- ("suboffsets", c_ssize_p),
- ("internal", c_void_p),
- ]
-
- PyObject_GetBuffer = pythonapi.PyObject_GetBuffer
- PyBuffer_Release = pythonapi.PyBuffer_Release
-
- def get_buffer(obj, writable=False):
- buf = Py_buffer()
- flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE
- PyObject_GetBuffer(py_object(obj), byref(buf), flags)
-
- try:
- buffer_type = c_char * buf.len
- return buffer_type.from_address(buf.buf)
- finally:
- PyBuffer_Release(byref(buf))
-
-
-class _WindowsConsoleRawIOBase(io.RawIOBase):
- def __init__(self, handle):
- self.handle = handle
-
- def isatty(self):
- super().isatty()
- return True
-
-
-class _WindowsConsoleReader(_WindowsConsoleRawIOBase):
- def readable(self):
- return True
-
- def readinto(self, b):
- bytes_to_be_read = len(b)
- if not bytes_to_be_read:
- return 0
- elif bytes_to_be_read % 2:
- raise ValueError(
- "cannot read odd number of bytes from UTF-16-LE encoded console"
- )
-
- buffer = get_buffer(b, writable=True)
- code_units_to_be_read = bytes_to_be_read // 2
- code_units_read = c_ulong()
-
- rv = ReadConsoleW(
- HANDLE(self.handle),
- buffer,
- code_units_to_be_read,
- byref(code_units_read),
- None,
- )
- if GetLastError() == ERROR_OPERATION_ABORTED:
- # wait for KeyboardInterrupt
- time.sleep(0.1)
- if not rv:
- raise OSError(f"Windows error: {GetLastError()}")
-
- if buffer[0] == EOF:
- return 0
- return 2 * code_units_read.value
-
-
-class _WindowsConsoleWriter(_WindowsConsoleRawIOBase):
- def writable(self):
- return True
-
- @staticmethod
- def _get_error_message(errno):
- if errno == ERROR_SUCCESS:
- return "ERROR_SUCCESS"
- elif errno == ERROR_NOT_ENOUGH_MEMORY:
- return "ERROR_NOT_ENOUGH_MEMORY"
- return f"Windows error {errno}"
-
- def write(self, b):
- bytes_to_be_written = len(b)
- buf = get_buffer(b)
- code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2
- code_units_written = c_ulong()
-
- WriteConsoleW(
- HANDLE(self.handle),
- buf,
- code_units_to_be_written,
- byref(code_units_written),
- None,
- )
- bytes_written = 2 * code_units_written.value
-
- if bytes_written == 0 and bytes_to_be_written > 0:
- raise OSError(self._get_error_message(GetLastError()))
- return bytes_written
-
-
-class ConsoleStream:
- def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None:
- self._text_stream = text_stream
- self.buffer = byte_stream
-
- @property
- def name(self) -> str:
- return self.buffer.name
-
- def write(self, x: t.AnyStr) -> int:
- if isinstance(x, str):
- return self._text_stream.write(x)
- try:
- self.flush()
- except Exception:
- pass
- return self.buffer.write(x)
-
- def writelines(self, lines: t.Iterable[t.AnyStr]) -> None:
- for line in lines:
- self.write(line)
-
- def __getattr__(self, name: str) -> t.Any:
- return getattr(self._text_stream, name)
-
- def isatty(self) -> bool:
- return self.buffer.isatty()
-
- def __repr__(self):
- return f""
-
-
-def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO:
- text_stream = _NonClosingTextIOWrapper(
- io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)),
- "utf-16-le",
- "strict",
- line_buffering=True,
- )
- return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream))
-
-
-def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO:
- text_stream = _NonClosingTextIOWrapper(
- io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)),
- "utf-16-le",
- "strict",
- line_buffering=True,
- )
- return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream))
-
-
-def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO:
- text_stream = _NonClosingTextIOWrapper(
- io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)),
- "utf-16-le",
- "strict",
- line_buffering=True,
- )
- return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream))
-
-
-_stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = {
- 0: _get_text_stdin,
- 1: _get_text_stdout,
- 2: _get_text_stderr,
-}
-
-
-def _is_console(f: t.TextIO) -> bool:
- if not hasattr(f, "fileno"):
- return False
-
- try:
- fileno = f.fileno()
- except (OSError, io.UnsupportedOperation):
- return False
-
- handle = msvcrt.get_osfhandle(fileno)
- return bool(GetConsoleMode(handle, byref(DWORD())))
-
-
-def _get_windows_console_stream(
- f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str]
-) -> t.Optional[t.TextIO]:
- if (
- get_buffer is not None
- and encoding in {"utf-16-le", None}
- and errors in {"strict", None}
- and _is_console(f)
- ):
- func = _stream_factories.get(f.fileno())
- if func is not None:
- b = getattr(f, "buffer", None)
-
- if b is None:
- return None
-
- return func(b)
diff --git a/venv/lib/python3.9/site-packages/click/core.py b/venv/lib/python3.9/site-packages/click/core.py
deleted file mode 100644
index e2ccf59..0000000
--- a/venv/lib/python3.9/site-packages/click/core.py
+++ /dev/null
@@ -1,2957 +0,0 @@
-import enum
-import errno
-import os
-import sys
-import typing
-import typing as t
-from collections import abc
-from contextlib import contextmanager
-from contextlib import ExitStack
-from functools import partial
-from functools import update_wrapper
-from gettext import gettext as _
-from gettext import ngettext
-from itertools import repeat
-
-from . import types
-from ._unicodefun import _verify_python_env
-from .exceptions import Abort
-from .exceptions import BadParameter
-from .exceptions import ClickException
-from .exceptions import Exit
-from .exceptions import MissingParameter
-from .exceptions import UsageError
-from .formatting import HelpFormatter
-from .formatting import join_options
-from .globals import pop_context
-from .globals import push_context
-from .parser import _flag_needs_value
-from .parser import OptionParser
-from .parser import split_opt
-from .termui import confirm
-from .termui import prompt
-from .termui import style
-from .utils import _detect_program_name
-from .utils import _expand_args
-from .utils import echo
-from .utils import make_default_short_help
-from .utils import make_str
-from .utils import PacifyFlushWrapper
-
-if t.TYPE_CHECKING:
- import typing_extensions as te
- from .shell_completion import CompletionItem
-
-F = t.TypeVar("F", bound=t.Callable[..., t.Any])
-V = t.TypeVar("V")
-
-
-def _fast_exit(code: int) -> "te.NoReturn":
- """Low-level exit that skips Python's cleanup but speeds up exit by
- about 10ms for things like shell completion.
-
- :param code: Exit code.
- """
- sys.stdout.flush()
- sys.stderr.flush()
- os._exit(code)
-
-
-def _complete_visible_commands(
- ctx: "Context", incomplete: str
-) -> t.Iterator[t.Tuple[str, "Command"]]:
- """List all the subcommands of a group that start with the
- incomplete value and aren't hidden.
-
- :param ctx: Invocation context for the group.
- :param incomplete: Value being completed. May be empty.
- """
- multi = t.cast(MultiCommand, ctx.command)
-
- for name in multi.list_commands(ctx):
- if name.startswith(incomplete):
- command = multi.get_command(ctx, name)
-
- if command is not None and not command.hidden:
- yield name, command
-
-
-def _check_multicommand(
- base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False
-) -> None:
- if not base_command.chain or not isinstance(cmd, MultiCommand):
- return
- if register:
- hint = (
- "It is not possible to add multi commands as children to"
- " another multi command that is in chain mode."
- )
- else:
- hint = (
- "Found a multi command as subcommand to a multi command"
- " that is in chain mode. This is not supported."
- )
- raise RuntimeError(
- f"{hint}. Command {base_command.name!r} is set to chain and"
- f" {cmd_name!r} was added as a subcommand but it in itself is a"
- f" multi command. ({cmd_name!r} is a {type(cmd).__name__}"
- f" within a chained {type(base_command).__name__} named"
- f" {base_command.name!r})."
- )
-
-
-def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]:
- return list(zip(*repeat(iter(iterable), batch_size)))
-
-
-@contextmanager
-def augment_usage_errors(
- ctx: "Context", param: t.Optional["Parameter"] = None
-) -> t.Iterator[None]:
- """Context manager that attaches extra information to exceptions."""
- try:
- yield
- except BadParameter as e:
- if e.ctx is None:
- e.ctx = ctx
- if param is not None and e.param is None:
- e.param = param
- raise
- except UsageError as e:
- if e.ctx is None:
- e.ctx = ctx
- raise
-
-
-def iter_params_for_processing(
- invocation_order: t.Sequence["Parameter"],
- declaration_order: t.Sequence["Parameter"],
-) -> t.List["Parameter"]:
- """Given a sequence of parameters in the order as should be considered
- for processing and an iterable of parameters that exist, this returns
- a list in the correct order as they should be processed.
- """
-
- def sort_key(item: "Parameter") -> t.Tuple[bool, float]:
- try:
- idx: float = invocation_order.index(item)
- except ValueError:
- idx = float("inf")
-
- return not item.is_eager, idx
-
- return sorted(declaration_order, key=sort_key)
-
-
-class ParameterSource(enum.Enum):
- """This is an :class:`~enum.Enum` that indicates the source of a
- parameter's value.
-
- Use :meth:`click.Context.get_parameter_source` to get the
- source for a parameter by name.
-
- .. versionchanged:: 8.0
- Use :class:`~enum.Enum` and drop the ``validate`` method.
-
- .. versionchanged:: 8.0
- Added the ``PROMPT`` value.
- """
-
- COMMANDLINE = enum.auto()
- """The value was provided by the command line args."""
- ENVIRONMENT = enum.auto()
- """The value was provided with an environment variable."""
- DEFAULT = enum.auto()
- """Used the default specified by the parameter."""
- DEFAULT_MAP = enum.auto()
- """Used a default provided by :attr:`Context.default_map`."""
- PROMPT = enum.auto()
- """Used a prompt to confirm a default or provide a value."""
-
-
-class Context:
- """The context is a special internal object that holds state relevant
- for the script execution at every single level. It's normally invisible
- to commands unless they opt-in to getting access to it.
-
- The context is useful as it can pass internal objects around and can
- control special execution features such as reading data from
- environment variables.
-
- A context can be used as context manager in which case it will call
- :meth:`close` on teardown.
-
- :param command: the command class for this context.
- :param parent: the parent context.
- :param info_name: the info name for this invocation. Generally this
- is the most descriptive name for the script or
- command. For the toplevel script it is usually
- the name of the script, for commands below it it's
- the name of the script.
- :param obj: an arbitrary object of user data.
- :param auto_envvar_prefix: the prefix to use for automatic environment
- variables. If this is `None` then reading
- from environment variables is disabled. This
- does not affect manually set environment
- variables which are always read.
- :param default_map: a dictionary (like object) with default values
- for parameters.
- :param terminal_width: the width of the terminal. The default is
- inherit from parent context. If no context
- defines the terminal width then auto
- detection will be applied.
- :param max_content_width: the maximum width for content rendered by
- Click (this currently only affects help
- pages). This defaults to 80 characters if
- not overridden. In other words: even if the
- terminal is larger than that, Click will not
- format things wider than 80 characters by
- default. In addition to that, formatters might
- add some safety mapping on the right.
- :param resilient_parsing: if this flag is enabled then Click will
- parse without any interactivity or callback
- invocation. Default values will also be
- ignored. This is useful for implementing
- things such as completion support.
- :param allow_extra_args: if this is set to `True` then extra arguments
- at the end will not raise an error and will be
- kept on the context. The default is to inherit
- from the command.
- :param allow_interspersed_args: if this is set to `False` then options
- and arguments cannot be mixed. The
- default is to inherit from the command.
- :param ignore_unknown_options: instructs click to ignore options it does
- not know and keeps them for later
- processing.
- :param help_option_names: optionally a list of strings that define how
- the default help parameter is named. The
- default is ``['--help']``.
- :param token_normalize_func: an optional function that is used to
- normalize tokens (options, choices,
- etc.). This for instance can be used to
- implement case insensitive behavior.
- :param color: controls if the terminal supports ANSI colors or not. The
- default is autodetection. This is only needed if ANSI
- codes are used in texts that Click prints which is by
- default not the case. This for instance would affect
- help output.
- :param show_default: Show defaults for all options. If not set,
- defaults to the value from a parent context. Overrides an
- option's ``show_default`` argument.
-
- .. versionchanged:: 8.0
- The ``show_default`` parameter defaults to the value from the
- parent context.
-
- .. versionchanged:: 7.1
- Added the ``show_default`` parameter.
-
- .. versionchanged:: 4.0
- Added the ``color``, ``ignore_unknown_options``, and
- ``max_content_width`` parameters.
-
- .. versionchanged:: 3.0
- Added the ``allow_extra_args`` and ``allow_interspersed_args``
- parameters.
-
- .. versionchanged:: 2.0
- Added the ``resilient_parsing``, ``help_option_names``, and
- ``token_normalize_func`` parameters.
- """
-
- #: The formatter class to create with :meth:`make_formatter`.
- #:
- #: .. versionadded:: 8.0
- formatter_class: t.Type["HelpFormatter"] = HelpFormatter
-
- def __init__(
- self,
- command: "Command",
- parent: t.Optional["Context"] = None,
- info_name: t.Optional[str] = None,
- obj: t.Optional[t.Any] = None,
- auto_envvar_prefix: t.Optional[str] = None,
- default_map: t.Optional[t.Dict[str, t.Any]] = None,
- terminal_width: t.Optional[int] = None,
- max_content_width: t.Optional[int] = None,
- resilient_parsing: bool = False,
- allow_extra_args: t.Optional[bool] = None,
- allow_interspersed_args: t.Optional[bool] = None,
- ignore_unknown_options: t.Optional[bool] = None,
- help_option_names: t.Optional[t.List[str]] = None,
- token_normalize_func: t.Optional[t.Callable[[str], str]] = None,
- color: t.Optional[bool] = None,
- show_default: t.Optional[bool] = None,
- ) -> None:
- #: the parent context or `None` if none exists.
- self.parent = parent
- #: the :class:`Command` for this context.
- self.command = command
- #: the descriptive information name
- self.info_name = info_name
- #: Map of parameter names to their parsed values. Parameters
- #: with ``expose_value=False`` are not stored.
- self.params: t.Dict[str, t.Any] = {}
- #: the leftover arguments.
- self.args: t.List[str] = []
- #: protected arguments. These are arguments that are prepended
- #: to `args` when certain parsing scenarios are encountered but
- #: must be never propagated to another arguments. This is used
- #: to implement nested parsing.
- self.protected_args: t.List[str] = []
-
- if obj is None and parent is not None:
- obj = parent.obj
-
- #: the user object stored.
- self.obj: t.Any = obj
- self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {})
-
- #: A dictionary (-like object) with defaults for parameters.
- if (
- default_map is None
- and info_name is not None
- and parent is not None
- and parent.default_map is not None
- ):
- default_map = parent.default_map.get(info_name)
-
- self.default_map: t.Optional[t.Dict[str, t.Any]] = default_map
-
- #: This flag indicates if a subcommand is going to be executed. A
- #: group callback can use this information to figure out if it's
- #: being executed directly or because the execution flow passes
- #: onwards to a subcommand. By default it's None, but it can be
- #: the name of the subcommand to execute.
- #:
- #: If chaining is enabled this will be set to ``'*'`` in case
- #: any commands are executed. It is however not possible to
- #: figure out which ones. If you require this knowledge you
- #: should use a :func:`result_callback`.
- self.invoked_subcommand: t.Optional[str] = None
-
- if terminal_width is None and parent is not None:
- terminal_width = parent.terminal_width
-
- #: The width of the terminal (None is autodetection).
- self.terminal_width: t.Optional[int] = terminal_width
-
- if max_content_width is None and parent is not None:
- max_content_width = parent.max_content_width
-
- #: The maximum width of formatted content (None implies a sensible
- #: default which is 80 for most things).
- self.max_content_width: t.Optional[int] = max_content_width
-
- if allow_extra_args is None:
- allow_extra_args = command.allow_extra_args
-
- #: Indicates if the context allows extra args or if it should
- #: fail on parsing.
- #:
- #: .. versionadded:: 3.0
- self.allow_extra_args = allow_extra_args
-
- if allow_interspersed_args is None:
- allow_interspersed_args = command.allow_interspersed_args
-
- #: Indicates if the context allows mixing of arguments and
- #: options or not.
- #:
- #: .. versionadded:: 3.0
- self.allow_interspersed_args: bool = allow_interspersed_args
-
- if ignore_unknown_options is None:
- ignore_unknown_options = command.ignore_unknown_options
-
- #: Instructs click to ignore options that a command does not
- #: understand and will store it on the context for later
- #: processing. This is primarily useful for situations where you
- #: want to call into external programs. Generally this pattern is
- #: strongly discouraged because it's not possibly to losslessly
- #: forward all arguments.
- #:
- #: .. versionadded:: 4.0
- self.ignore_unknown_options: bool = ignore_unknown_options
-
- if help_option_names is None:
- if parent is not None:
- help_option_names = parent.help_option_names
- else:
- help_option_names = ["--help"]
-
- #: The names for the help options.
- self.help_option_names: t.List[str] = help_option_names
-
- if token_normalize_func is None and parent is not None:
- token_normalize_func = parent.token_normalize_func
-
- #: An optional normalization function for tokens. This is
- #: options, choices, commands etc.
- self.token_normalize_func: t.Optional[
- t.Callable[[str], str]
- ] = token_normalize_func
-
- #: Indicates if resilient parsing is enabled. In that case Click
- #: will do its best to not cause any failures and default values
- #: will be ignored. Useful for completion.
- self.resilient_parsing: bool = resilient_parsing
-
- # If there is no envvar prefix yet, but the parent has one and
- # the command on this level has a name, we can expand the envvar
- # prefix automatically.
- if auto_envvar_prefix is None:
- if (
- parent is not None
- and parent.auto_envvar_prefix is not None
- and self.info_name is not None
- ):
- auto_envvar_prefix = (
- f"{parent.auto_envvar_prefix}_{self.info_name.upper()}"
- )
- else:
- auto_envvar_prefix = auto_envvar_prefix.upper()
-
- if auto_envvar_prefix is not None:
- auto_envvar_prefix = auto_envvar_prefix.replace("-", "_")
-
- self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix
-
- if color is None and parent is not None:
- color = parent.color
-
- #: Controls if styling output is wanted or not.
- self.color: t.Optional[bool] = color
-
- if show_default is None and parent is not None:
- show_default = parent.show_default
-
- #: Show option default values when formatting help text.
- self.show_default: t.Optional[bool] = show_default
-
- self._close_callbacks: t.List[t.Callable[[], t.Any]] = []
- self._depth = 0
- self._parameter_source: t.Dict[str, ParameterSource] = {}
- self._exit_stack = ExitStack()
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- """Gather information that could be useful for a tool generating
- user-facing documentation. This traverses the entire CLI
- structure.
-
- .. code-block:: python
-
- with Context(cli) as ctx:
- info = ctx.to_info_dict()
-
- .. versionadded:: 8.0
- """
- return {
- "command": self.command.to_info_dict(self),
- "info_name": self.info_name,
- "allow_extra_args": self.allow_extra_args,
- "allow_interspersed_args": self.allow_interspersed_args,
- "ignore_unknown_options": self.ignore_unknown_options,
- "auto_envvar_prefix": self.auto_envvar_prefix,
- }
-
- def __enter__(self) -> "Context":
- self._depth += 1
- push_context(self)
- return self
-
- def __exit__(self, exc_type, exc_value, tb): # type: ignore
- self._depth -= 1
- if self._depth == 0:
- self.close()
- pop_context()
-
- @contextmanager
- def scope(self, cleanup: bool = True) -> t.Iterator["Context"]:
- """This helper method can be used with the context object to promote
- it to the current thread local (see :func:`get_current_context`).
- The default behavior of this is to invoke the cleanup functions which
- can be disabled by setting `cleanup` to `False`. The cleanup
- functions are typically used for things such as closing file handles.
-
- If the cleanup is intended the context object can also be directly
- used as a context manager.
-
- Example usage::
-
- with ctx.scope():
- assert get_current_context() is ctx
-
- This is equivalent::
-
- with ctx:
- assert get_current_context() is ctx
-
- .. versionadded:: 5.0
-
- :param cleanup: controls if the cleanup functions should be run or
- not. The default is to run these functions. In
- some situations the context only wants to be
- temporarily pushed in which case this can be disabled.
- Nested pushes automatically defer the cleanup.
- """
- if not cleanup:
- self._depth += 1
- try:
- with self as rv:
- yield rv
- finally:
- if not cleanup:
- self._depth -= 1
-
- @property
- def meta(self) -> t.Dict[str, t.Any]:
- """This is a dictionary which is shared with all the contexts
- that are nested. It exists so that click utilities can store some
- state here if they need to. It is however the responsibility of
- that code to manage this dictionary well.
-
- The keys are supposed to be unique dotted strings. For instance
- module paths are a good choice for it. What is stored in there is
- irrelevant for the operation of click. However what is important is
- that code that places data here adheres to the general semantics of
- the system.
-
- Example usage::
-
- LANG_KEY = f'{__name__}.lang'
-
- def set_language(value):
- ctx = get_current_context()
- ctx.meta[LANG_KEY] = value
-
- def get_language():
- return get_current_context().meta.get(LANG_KEY, 'en_US')
-
- .. versionadded:: 5.0
- """
- return self._meta
-
- def make_formatter(self) -> HelpFormatter:
- """Creates the :class:`~click.HelpFormatter` for the help and
- usage output.
-
- To quickly customize the formatter class used without overriding
- this method, set the :attr:`formatter_class` attribute.
-
- .. versionchanged:: 8.0
- Added the :attr:`formatter_class` attribute.
- """
- return self.formatter_class(
- width=self.terminal_width, max_width=self.max_content_width
- )
-
- def with_resource(self, context_manager: t.ContextManager[V]) -> V:
- """Register a resource as if it were used in a ``with``
- statement. The resource will be cleaned up when the context is
- popped.
-
- Uses :meth:`contextlib.ExitStack.enter_context`. It calls the
- resource's ``__enter__()`` method and returns the result. When
- the context is popped, it closes the stack, which calls the
- resource's ``__exit__()`` method.
-
- To register a cleanup function for something that isn't a
- context manager, use :meth:`call_on_close`. Or use something
- from :mod:`contextlib` to turn it into a context manager first.
-
- .. code-block:: python
-
- @click.group()
- @click.option("--name")
- @click.pass_context
- def cli(ctx):
- ctx.obj = ctx.with_resource(connect_db(name))
-
- :param context_manager: The context manager to enter.
- :return: Whatever ``context_manager.__enter__()`` returns.
-
- .. versionadded:: 8.0
- """
- return self._exit_stack.enter_context(context_manager)
-
- def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
- """Register a function to be called when the context tears down.
-
- This can be used to close resources opened during the script
- execution. Resources that support Python's context manager
- protocol which would be used in a ``with`` statement should be
- registered with :meth:`with_resource` instead.
-
- :param f: The function to execute on teardown.
- """
- return self._exit_stack.callback(f)
-
- def close(self) -> None:
- """Invoke all close callbacks registered with
- :meth:`call_on_close`, and exit all context managers entered
- with :meth:`with_resource`.
- """
- self._exit_stack.close()
- # In case the context is reused, create a new exit stack.
- self._exit_stack = ExitStack()
-
- @property
- def command_path(self) -> str:
- """The computed command path. This is used for the ``usage``
- information on the help page. It's automatically created by
- combining the info names of the chain of contexts to the root.
- """
- rv = ""
- if self.info_name is not None:
- rv = self.info_name
- if self.parent is not None:
- parent_command_path = [self.parent.command_path]
-
- if isinstance(self.parent.command, Command):
- for param in self.parent.command.get_params(self):
- parent_command_path.extend(param.get_usage_pieces(self))
-
- rv = f"{' '.join(parent_command_path)} {rv}"
- return rv.lstrip()
-
- def find_root(self) -> "Context":
- """Finds the outermost context."""
- node = self
- while node.parent is not None:
- node = node.parent
- return node
-
- def find_object(self, object_type: t.Type[V]) -> t.Optional[V]:
- """Finds the closest object of a given type."""
- node: t.Optional["Context"] = self
-
- while node is not None:
- if isinstance(node.obj, object_type):
- return node.obj
-
- node = node.parent
-
- return None
-
- def ensure_object(self, object_type: t.Type[V]) -> V:
- """Like :meth:`find_object` but sets the innermost object to a
- new instance of `object_type` if it does not exist.
- """
- rv = self.find_object(object_type)
- if rv is None:
- self.obj = rv = object_type()
- return rv
-
- @typing.overload
- def lookup_default(
- self, name: str, call: "te.Literal[True]" = True
- ) -> t.Optional[t.Any]:
- ...
-
- @typing.overload
- def lookup_default(
- self, name: str, call: "te.Literal[False]" = ...
- ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
- ...
-
- def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]:
- """Get the default for a parameter from :attr:`default_map`.
-
- :param name: Name of the parameter.
- :param call: If the default is a callable, call it. Disable to
- return the callable instead.
-
- .. versionchanged:: 8.0
- Added the ``call`` parameter.
- """
- if self.default_map is not None:
- value = self.default_map.get(name)
-
- if call and callable(value):
- return value()
-
- return value
-
- return None
-
- def fail(self, message: str) -> "te.NoReturn":
- """Aborts the execution of the program with a specific error
- message.
-
- :param message: the error message to fail with.
- """
- raise UsageError(message, self)
-
- def abort(self) -> "te.NoReturn":
- """Aborts the script."""
- raise Abort()
-
- def exit(self, code: int = 0) -> "te.NoReturn":
- """Exits the application with a given exit code."""
- raise Exit(code)
-
- def get_usage(self) -> str:
- """Helper method to get formatted usage string for the current
- context and command.
- """
- return self.command.get_usage(self)
-
- def get_help(self) -> str:
- """Helper method to get formatted help page for the current
- context and command.
- """
- return self.command.get_help(self)
-
- def _make_sub_context(self, command: "Command") -> "Context":
- """Create a new context of the same type as this context, but
- for a new command.
-
- :meta private:
- """
- return type(self)(command, info_name=command.name, parent=self)
-
- def invoke(
- __self, # noqa: B902
- __callback: t.Union["Command", t.Callable[..., t.Any]],
- *args: t.Any,
- **kwargs: t.Any,
- ) -> t.Any:
- """Invokes a command callback in exactly the way it expects. There
- are two ways to invoke this method:
-
- 1. the first argument can be a callback and all other arguments and
- keyword arguments are forwarded directly to the function.
- 2. the first argument is a click command object. In that case all
- arguments are forwarded as well but proper click parameters
- (options and click arguments) must be keyword arguments and Click
- will fill in defaults.
-
- Note that before Click 3.2 keyword arguments were not properly filled
- in against the intention of this code and no context was created. For
- more information about this change and why it was done in a bugfix
- release see :ref:`upgrade-to-3.2`.
-
- .. versionchanged:: 8.0
- All ``kwargs`` are tracked in :attr:`params` so they will be
- passed if :meth:`forward` is called at multiple levels.
- """
- if isinstance(__callback, Command):
- other_cmd = __callback
-
- if other_cmd.callback is None:
- raise TypeError(
- "The given command does not have a callback that can be invoked."
- )
- else:
- __callback = other_cmd.callback
-
- ctx = __self._make_sub_context(other_cmd)
-
- for param in other_cmd.params:
- if param.name not in kwargs and param.expose_value:
- kwargs[param.name] = param.get_default(ctx) # type: ignore
-
- # Track all kwargs as params, so that forward() will pass
- # them on in subsequent calls.
- ctx.params.update(kwargs)
- else:
- ctx = __self
-
- with augment_usage_errors(__self):
- with ctx:
- return __callback(*args, **kwargs)
-
- def forward(
- __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # noqa: B902
- ) -> t.Any:
- """Similar to :meth:`invoke` but fills in default keyword
- arguments from the current context if the other command expects
- it. This cannot invoke callbacks directly, only other commands.
-
- .. versionchanged:: 8.0
- All ``kwargs`` are tracked in :attr:`params` so they will be
- passed if ``forward`` is called at multiple levels.
- """
- # Can only forward to other commands, not direct callbacks.
- if not isinstance(__cmd, Command):
- raise TypeError("Callback is not a command.")
-
- for param in __self.params:
- if param not in kwargs:
- kwargs[param] = __self.params[param]
-
- return __self.invoke(__cmd, *args, **kwargs)
-
- def set_parameter_source(self, name: str, source: ParameterSource) -> None:
- """Set the source of a parameter. This indicates the location
- from which the value of the parameter was obtained.
-
- :param name: The name of the parameter.
- :param source: A member of :class:`~click.core.ParameterSource`.
- """
- self._parameter_source[name] = source
-
- def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]:
- """Get the source of a parameter. This indicates the location
- from which the value of the parameter was obtained.
-
- This can be useful for determining when a user specified a value
- on the command line that is the same as the default value. It
- will be :attr:`~click.core.ParameterSource.DEFAULT` only if the
- value was actually taken from the default.
-
- :param name: The name of the parameter.
- :rtype: ParameterSource
-
- .. versionchanged:: 8.0
- Returns ``None`` if the parameter was not provided from any
- source.
- """
- return self._parameter_source.get(name)
-
-
-class BaseCommand:
- """The base command implements the minimal API contract of commands.
- Most code will never use this as it does not implement a lot of useful
- functionality but it can act as the direct subclass of alternative
- parsing methods that do not depend on the Click parser.
-
- For instance, this can be used to bridge Click and other systems like
- argparse or docopt.
-
- Because base commands do not implement a lot of the API that other
- parts of Click take for granted, they are not supported for all
- operations. For instance, they cannot be used with the decorators
- usually and they have no built-in callback system.
-
- .. versionchanged:: 2.0
- Added the `context_settings` parameter.
-
- :param name: the name of the command to use unless a group overrides it.
- :param context_settings: an optional dictionary with defaults that are
- passed to the context object.
- """
-
- #: The context class to create with :meth:`make_context`.
- #:
- #: .. versionadded:: 8.0
- context_class: t.Type[Context] = Context
- #: the default for the :attr:`Context.allow_extra_args` flag.
- allow_extra_args = False
- #: the default for the :attr:`Context.allow_interspersed_args` flag.
- allow_interspersed_args = True
- #: the default for the :attr:`Context.ignore_unknown_options` flag.
- ignore_unknown_options = False
-
- def __init__(
- self,
- name: t.Optional[str],
- context_settings: t.Optional[t.Dict[str, t.Any]] = None,
- ) -> None:
- #: the name the command thinks it has. Upon registering a command
- #: on a :class:`Group` the group will default the command name
- #: with this information. You should instead use the
- #: :class:`Context`\'s :attr:`~Context.info_name` attribute.
- self.name = name
-
- if context_settings is None:
- context_settings = {}
-
- #: an optional dictionary with defaults passed to the context.
- self.context_settings: t.Dict[str, t.Any] = context_settings
-
- def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]:
- """Gather information that could be useful for a tool generating
- user-facing documentation. This traverses the entire structure
- below this command.
-
- Use :meth:`click.Context.to_info_dict` to traverse the entire
- CLI structure.
-
- :param ctx: A :class:`Context` representing this command.
-
- .. versionadded:: 8.0
- """
- return {"name": self.name}
-
- def __repr__(self) -> str:
- return f"<{self.__class__.__name__} {self.name}>"
-
- def get_usage(self, ctx: Context) -> str:
- raise NotImplementedError("Base commands cannot get usage")
-
- def get_help(self, ctx: Context) -> str:
- raise NotImplementedError("Base commands cannot get help")
-
- def make_context(
- self,
- info_name: t.Optional[str],
- args: t.List[str],
- parent: t.Optional[Context] = None,
- **extra: t.Any,
- ) -> Context:
- """This function when given an info name and arguments will kick
- off the parsing and create a new :class:`Context`. It does not
- invoke the actual command callback though.
-
- To quickly customize the context class used without overriding
- this method, set the :attr:`context_class` attribute.
-
- :param info_name: the info name for this invocation. Generally this
- is the most descriptive name for the script or
- command. For the toplevel script it's usually
- the name of the script, for commands below it it's
- the name of the command.
- :param args: the arguments to parse as list of strings.
- :param parent: the parent context if available.
- :param extra: extra keyword arguments forwarded to the context
- constructor.
-
- .. versionchanged:: 8.0
- Added the :attr:`context_class` attribute.
- """
- for key, value in self.context_settings.items():
- if key not in extra:
- extra[key] = value
-
- ctx = self.context_class(
- self, info_name=info_name, parent=parent, **extra # type: ignore
- )
-
- with ctx.scope(cleanup=False):
- self.parse_args(ctx, args)
- return ctx
-
- def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]:
- """Given a context and a list of arguments this creates the parser
- and parses the arguments, then modifies the context as necessary.
- This is automatically invoked by :meth:`make_context`.
- """
- raise NotImplementedError("Base commands do not know how to parse arguments.")
-
- def invoke(self, ctx: Context) -> t.Any:
- """Given a context, this invokes the command. The default
- implementation is raising a not implemented error.
- """
- raise NotImplementedError("Base commands are not invokable by default")
-
- def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
- """Return a list of completions for the incomplete value. Looks
- at the names of chained multi-commands.
-
- Any command could be part of a chained multi-command, so sibling
- commands are valid at any point during command completion. Other
- command classes will return more completions.
-
- :param ctx: Invocation context for this command.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- from click.shell_completion import CompletionItem
-
- results: t.List["CompletionItem"] = []
-
- while ctx.parent is not None:
- ctx = ctx.parent
-
- if isinstance(ctx.command, MultiCommand) and ctx.command.chain:
- results.extend(
- CompletionItem(name, help=command.get_short_help_str())
- for name, command in _complete_visible_commands(ctx, incomplete)
- if name not in ctx.protected_args
- )
-
- return results
-
- @typing.overload
- def main(
- self,
- args: t.Optional[t.Sequence[str]] = None,
- prog_name: t.Optional[str] = None,
- complete_var: t.Optional[str] = None,
- standalone_mode: "te.Literal[True]" = True,
- **extra: t.Any,
- ) -> "te.NoReturn":
- ...
-
- @typing.overload
- def main(
- self,
- args: t.Optional[t.Sequence[str]] = None,
- prog_name: t.Optional[str] = None,
- complete_var: t.Optional[str] = None,
- standalone_mode: bool = ...,
- **extra: t.Any,
- ) -> t.Any:
- ...
-
- def main(
- self,
- args: t.Optional[t.Sequence[str]] = None,
- prog_name: t.Optional[str] = None,
- complete_var: t.Optional[str] = None,
- standalone_mode: bool = True,
- windows_expand_args: bool = True,
- **extra: t.Any,
- ) -> t.Any:
- """This is the way to invoke a script with all the bells and
- whistles as a command line application. This will always terminate
- the application after a call. If this is not wanted, ``SystemExit``
- needs to be caught.
-
- This method is also available by directly calling the instance of
- a :class:`Command`.
-
- :param args: the arguments that should be used for parsing. If not
- provided, ``sys.argv[1:]`` is used.
- :param prog_name: the program name that should be used. By default
- the program name is constructed by taking the file
- name from ``sys.argv[0]``.
- :param complete_var: the environment variable that controls the
- bash completion support. The default is
- ``"__COMPLETE"`` with prog_name in
- uppercase.
- :param standalone_mode: the default behavior is to invoke the script
- in standalone mode. Click will then
- handle exceptions and convert them into
- error messages and the function will never
- return but shut down the interpreter. If
- this is set to `False` they will be
- propagated to the caller and the return
- value of this function is the return value
- of :meth:`invoke`.
- :param windows_expand_args: Expand glob patterns, user dir, and
- env vars in command line args on Windows.
- :param extra: extra keyword arguments are forwarded to the context
- constructor. See :class:`Context` for more information.
-
- .. versionchanged:: 8.0.1
- Added the ``windows_expand_args`` parameter to allow
- disabling command line arg expansion on Windows.
-
- .. versionchanged:: 8.0
- When taking arguments from ``sys.argv`` on Windows, glob
- patterns, user dir, and env vars are expanded.
-
- .. versionchanged:: 3.0
- Added the ``standalone_mode`` parameter.
- """
- # Verify that the environment is configured correctly, or reject
- # further execution to avoid a broken script.
- _verify_python_env()
-
- if args is None:
- args = sys.argv[1:]
-
- if os.name == "nt" and windows_expand_args:
- args = _expand_args(args)
- else:
- args = list(args)
-
- if prog_name is None:
- prog_name = _detect_program_name()
-
- # Process shell completion requests and exit early.
- self._main_shell_completion(extra, prog_name, complete_var)
-
- try:
- try:
- with self.make_context(prog_name, args, **extra) as ctx:
- rv = self.invoke(ctx)
- if not standalone_mode:
- return rv
- # it's not safe to `ctx.exit(rv)` here!
- # note that `rv` may actually contain data like "1" which
- # has obvious effects
- # more subtle case: `rv=[None, None]` can come out of
- # chained commands which all returned `None` -- so it's not
- # even always obvious that `rv` indicates success/failure
- # by its truthiness/falsiness
- ctx.exit()
- except (EOFError, KeyboardInterrupt):
- echo(file=sys.stderr)
- raise Abort()
- except ClickException as e:
- if not standalone_mode:
- raise
- e.show()
- sys.exit(e.exit_code)
- except OSError as e:
- if e.errno == errno.EPIPE:
- sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout))
- sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr))
- sys.exit(1)
- else:
- raise
- except Exit as e:
- if standalone_mode:
- sys.exit(e.exit_code)
- else:
- # in non-standalone mode, return the exit code
- # note that this is only reached if `self.invoke` above raises
- # an Exit explicitly -- thus bypassing the check there which
- # would return its result
- # the results of non-standalone execution may therefore be
- # somewhat ambiguous: if there are codepaths which lead to
- # `ctx.exit(1)` and to `return 1`, the caller won't be able to
- # tell the difference between the two
- return e.exit_code
- except Abort:
- if not standalone_mode:
- raise
- echo(_("Aborted!"), file=sys.stderr)
- sys.exit(1)
-
- def _main_shell_completion(
- self,
- ctx_args: t.Dict[str, t.Any],
- prog_name: str,
- complete_var: t.Optional[str] = None,
- ) -> None:
- """Check if the shell is asking for tab completion, process
- that, then exit early. Called from :meth:`main` before the
- program is invoked.
-
- :param prog_name: Name of the executable in the shell.
- :param complete_var: Name of the environment variable that holds
- the completion instruction. Defaults to
- ``_{PROG_NAME}_COMPLETE``.
- """
- if complete_var is None:
- complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper()
-
- instruction = os.environ.get(complete_var)
-
- if not instruction:
- return
-
- from .shell_completion import shell_complete
-
- rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction)
- _fast_exit(rv)
-
- def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
- """Alias for :meth:`main`."""
- return self.main(*args, **kwargs)
-
-
-class Command(BaseCommand):
- """Commands are the basic building block of command line interfaces in
- Click. A basic command handles command line parsing and might dispatch
- more parsing to commands nested below it.
-
- .. versionchanged:: 2.0
- Added the `context_settings` parameter.
- .. versionchanged:: 8.0
- Added repr showing the command name
- .. versionchanged:: 7.1
- Added the `no_args_is_help` parameter.
-
- :param name: the name of the command to use unless a group overrides it.
- :param context_settings: an optional dictionary with defaults that are
- passed to the context object.
- :param callback: the callback to invoke. This is optional.
- :param params: the parameters to register with this command. This can
- be either :class:`Option` or :class:`Argument` objects.
- :param help: the help string to use for this command.
- :param epilog: like the help string but it's printed at the end of the
- help page after everything else.
- :param short_help: the short help to use for this command. This is
- shown on the command listing of the parent command.
- :param add_help_option: by default each command registers a ``--help``
- option. This can be disabled by this parameter.
- :param no_args_is_help: this controls what happens if no arguments are
- provided. This option is disabled by default.
- If enabled this will add ``--help`` as argument
- if no arguments are passed
- :param hidden: hide this command from help outputs.
-
- :param deprecated: issues a message indicating that
- the command is deprecated.
- """
-
- def __init__(
- self,
- name: t.Optional[str],
- context_settings: t.Optional[t.Dict[str, t.Any]] = None,
- callback: t.Optional[t.Callable[..., t.Any]] = None,
- params: t.Optional[t.List["Parameter"]] = None,
- help: t.Optional[str] = None,
- epilog: t.Optional[str] = None,
- short_help: t.Optional[str] = None,
- options_metavar: t.Optional[str] = "[OPTIONS]",
- add_help_option: bool = True,
- no_args_is_help: bool = False,
- hidden: bool = False,
- deprecated: bool = False,
- ) -> None:
- super().__init__(name, context_settings)
- #: the callback to execute when the command fires. This might be
- #: `None` in which case nothing happens.
- self.callback = callback
- #: the list of parameters for this command in the order they
- #: should show up in the help page and execute. Eager parameters
- #: will automatically be handled before non eager ones.
- self.params: t.List["Parameter"] = params or []
-
- # if a form feed (page break) is found in the help text, truncate help
- # text to the content preceding the first form feed
- if help and "\f" in help:
- help = help.split("\f", 1)[0]
-
- self.help = help
- self.epilog = epilog
- self.options_metavar = options_metavar
- self.short_help = short_help
- self.add_help_option = add_help_option
- self.no_args_is_help = no_args_is_help
- self.hidden = hidden
- self.deprecated = deprecated
-
- def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict(ctx)
- info_dict.update(
- params=[param.to_info_dict() for param in self.get_params(ctx)],
- help=self.help,
- epilog=self.epilog,
- short_help=self.short_help,
- hidden=self.hidden,
- deprecated=self.deprecated,
- )
- return info_dict
-
- def get_usage(self, ctx: Context) -> str:
- """Formats the usage line into a string and returns it.
-
- Calls :meth:`format_usage` internally.
- """
- formatter = ctx.make_formatter()
- self.format_usage(ctx, formatter)
- return formatter.getvalue().rstrip("\n")
-
- def get_params(self, ctx: Context) -> t.List["Parameter"]:
- rv = self.params
- help_option = self.get_help_option(ctx)
-
- if help_option is not None:
- rv = [*rv, help_option]
-
- return rv
-
- def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None:
- """Writes the usage line into the formatter.
-
- This is a low-level method called by :meth:`get_usage`.
- """
- pieces = self.collect_usage_pieces(ctx)
- formatter.write_usage(ctx.command_path, " ".join(pieces))
-
- def collect_usage_pieces(self, ctx: Context) -> t.List[str]:
- """Returns all the pieces that go into the usage line and returns
- it as a list of strings.
- """
- rv = [self.options_metavar] if self.options_metavar else []
-
- for param in self.get_params(ctx):
- rv.extend(param.get_usage_pieces(ctx))
-
- return rv
-
- def get_help_option_names(self, ctx: Context) -> t.List[str]:
- """Returns the names for the help option."""
- all_names = set(ctx.help_option_names)
- for param in self.params:
- all_names.difference_update(param.opts)
- all_names.difference_update(param.secondary_opts)
- return list(all_names)
-
- def get_help_option(self, ctx: Context) -> t.Optional["Option"]:
- """Returns the help option object."""
- help_options = self.get_help_option_names(ctx)
-
- if not help_options or not self.add_help_option:
- return None
-
- def show_help(ctx: Context, param: "Parameter", value: str) -> None:
- if value and not ctx.resilient_parsing:
- echo(ctx.get_help(), color=ctx.color)
- ctx.exit()
-
- return Option(
- help_options,
- is_flag=True,
- is_eager=True,
- expose_value=False,
- callback=show_help,
- help=_("Show this message and exit."),
- )
-
- def make_parser(self, ctx: Context) -> OptionParser:
- """Creates the underlying option parser for this command."""
- parser = OptionParser(ctx)
- for param in self.get_params(ctx):
- param.add_to_parser(parser, ctx)
- return parser
-
- def get_help(self, ctx: Context) -> str:
- """Formats the help into a string and returns it.
-
- Calls :meth:`format_help` internally.
- """
- formatter = ctx.make_formatter()
- self.format_help(ctx, formatter)
- return formatter.getvalue().rstrip("\n")
-
- def get_short_help_str(self, limit: int = 45) -> str:
- """Gets short help for the command or makes it by shortening the
- long help string.
- """
- text = self.short_help or ""
-
- if not text and self.help:
- text = make_default_short_help(self.help, limit)
-
- if self.deprecated:
- text = _("(Deprecated) {text}").format(text=text)
-
- return text.strip()
-
- def format_help(self, ctx: Context, formatter: HelpFormatter) -> None:
- """Writes the help into the formatter if it exists.
-
- This is a low-level method called by :meth:`get_help`.
-
- This calls the following methods:
-
- - :meth:`format_usage`
- - :meth:`format_help_text`
- - :meth:`format_options`
- - :meth:`format_epilog`
- """
- self.format_usage(ctx, formatter)
- self.format_help_text(ctx, formatter)
- self.format_options(ctx, formatter)
- self.format_epilog(ctx, formatter)
-
- def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None:
- """Writes the help text to the formatter if it exists."""
- text = self.help or ""
-
- if self.deprecated:
- text = _("(Deprecated) {text}").format(text=text)
-
- if text:
- formatter.write_paragraph()
-
- with formatter.indentation():
- formatter.write_text(text)
-
- def format_options(self, ctx: Context, formatter: HelpFormatter) -> None:
- """Writes all the options into the formatter if they exist."""
- opts = []
- for param in self.get_params(ctx):
- rv = param.get_help_record(ctx)
- if rv is not None:
- opts.append(rv)
-
- if opts:
- with formatter.section(_("Options")):
- formatter.write_dl(opts)
-
- def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None:
- """Writes the epilog into the formatter if it exists."""
- if self.epilog:
- formatter.write_paragraph()
- with formatter.indentation():
- formatter.write_text(self.epilog)
-
- def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]:
- if not args and self.no_args_is_help and not ctx.resilient_parsing:
- echo(ctx.get_help(), color=ctx.color)
- ctx.exit()
-
- parser = self.make_parser(ctx)
- opts, args, param_order = parser.parse_args(args=args)
-
- for param in iter_params_for_processing(param_order, self.get_params(ctx)):
- value, args = param.handle_parse_result(ctx, opts, args)
-
- if args and not ctx.allow_extra_args and not ctx.resilient_parsing:
- ctx.fail(
- ngettext(
- "Got unexpected extra argument ({args})",
- "Got unexpected extra arguments ({args})",
- len(args),
- ).format(args=" ".join(map(str, args)))
- )
-
- ctx.args = args
- return args
-
- def invoke(self, ctx: Context) -> t.Any:
- """Given a context, this invokes the attached callback (if it exists)
- in the right way.
- """
- if self.deprecated:
- message = _(
- "DeprecationWarning: The command {name!r} is deprecated."
- ).format(name=self.name)
- echo(style(message, fg="red"), err=True)
-
- if self.callback is not None:
- return ctx.invoke(self.callback, **ctx.params)
-
- def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
- """Return a list of completions for the incomplete value. Looks
- at the names of options and chained multi-commands.
-
- :param ctx: Invocation context for this command.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- from click.shell_completion import CompletionItem
-
- results: t.List["CompletionItem"] = []
-
- if incomplete and not incomplete[0].isalnum():
- for param in self.get_params(ctx):
- if (
- not isinstance(param, Option)
- or param.hidden
- or (
- not param.multiple
- and ctx.get_parameter_source(param.name) # type: ignore
- is ParameterSource.COMMANDLINE
- )
- ):
- continue
-
- results.extend(
- CompletionItem(name, help=param.help)
- for name in [*param.opts, *param.secondary_opts]
- if name.startswith(incomplete)
- )
-
- results.extend(super().shell_complete(ctx, incomplete))
- return results
-
-
-class MultiCommand(Command):
- """A multi command is the basic implementation of a command that
- dispatches to subcommands. The most common version is the
- :class:`Group`.
-
- :param invoke_without_command: this controls how the multi command itself
- is invoked. By default it's only invoked
- if a subcommand is provided.
- :param no_args_is_help: this controls what happens if no arguments are
- provided. This option is enabled by default if
- `invoke_without_command` is disabled or disabled
- if it's enabled. If enabled this will add
- ``--help`` as argument if no arguments are
- passed.
- :param subcommand_metavar: the string that is used in the documentation
- to indicate the subcommand place.
- :param chain: if this is set to `True` chaining of multiple subcommands
- is enabled. This restricts the form of commands in that
- they cannot have optional arguments but it allows
- multiple commands to be chained together.
- :param result_callback: The result callback to attach to this multi
- command. This can be set or changed later with the
- :meth:`result_callback` decorator.
- """
-
- allow_extra_args = True
- allow_interspersed_args = False
-
- def __init__(
- self,
- name: t.Optional[str] = None,
- invoke_without_command: bool = False,
- no_args_is_help: t.Optional[bool] = None,
- subcommand_metavar: t.Optional[str] = None,
- chain: bool = False,
- result_callback: t.Optional[t.Callable[..., t.Any]] = None,
- **attrs: t.Any,
- ) -> None:
- super().__init__(name, **attrs)
-
- if no_args_is_help is None:
- no_args_is_help = not invoke_without_command
-
- self.no_args_is_help = no_args_is_help
- self.invoke_without_command = invoke_without_command
-
- if subcommand_metavar is None:
- if chain:
- subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..."
- else:
- subcommand_metavar = "COMMAND [ARGS]..."
-
- self.subcommand_metavar = subcommand_metavar
- self.chain = chain
- # The result callback that is stored. This can be set or
- # overridden with the :func:`result_callback` decorator.
- self._result_callback = result_callback
-
- if self.chain:
- for param in self.params:
- if isinstance(param, Argument) and not param.required:
- raise RuntimeError(
- "Multi commands in chain mode cannot have"
- " optional arguments."
- )
-
- def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict(ctx)
- commands = {}
-
- for name in self.list_commands(ctx):
- command = self.get_command(ctx, name)
-
- if command is None:
- continue
-
- sub_ctx = ctx._make_sub_context(command)
-
- with sub_ctx.scope(cleanup=False):
- commands[name] = command.to_info_dict(sub_ctx)
-
- info_dict.update(commands=commands, chain=self.chain)
- return info_dict
-
- def collect_usage_pieces(self, ctx: Context) -> t.List[str]:
- rv = super().collect_usage_pieces(ctx)
- rv.append(self.subcommand_metavar)
- return rv
-
- def format_options(self, ctx: Context, formatter: HelpFormatter) -> None:
- super().format_options(ctx, formatter)
- self.format_commands(ctx, formatter)
-
- def result_callback(self, replace: bool = False) -> t.Callable[[F], F]:
- """Adds a result callback to the command. By default if a
- result callback is already registered this will chain them but
- this can be disabled with the `replace` parameter. The result
- callback is invoked with the return value of the subcommand
- (or the list of return values from all subcommands if chaining
- is enabled) as well as the parameters as they would be passed
- to the main callback.
-
- Example::
-
- @click.group()
- @click.option('-i', '--input', default=23)
- def cli(input):
- return 42
-
- @cli.result_callback()
- def process_result(result, input):
- return result + input
-
- :param replace: if set to `True` an already existing result
- callback will be removed.
-
- .. versionchanged:: 8.0
- Renamed from ``resultcallback``.
-
- .. versionadded:: 3.0
- """
-
- def decorator(f: F) -> F:
- old_callback = self._result_callback
-
- if old_callback is None or replace:
- self._result_callback = f
- return f
-
- def function(__value, *args, **kwargs): # type: ignore
- inner = old_callback(__value, *args, **kwargs) # type: ignore
- return f(inner, *args, **kwargs)
-
- self._result_callback = rv = update_wrapper(t.cast(F, function), f)
- return rv
-
- return decorator
-
- def resultcallback(self, replace: bool = False) -> t.Callable[[F], F]:
- import warnings
-
- warnings.warn(
- "'resultcallback' has been renamed to 'result_callback'."
- " The old name will be removed in Click 8.1.",
- DeprecationWarning,
- stacklevel=2,
- )
- return self.result_callback(replace=replace)
-
- def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None:
- """Extra format methods for multi methods that adds all the commands
- after the options.
- """
- commands = []
- for subcommand in self.list_commands(ctx):
- cmd = self.get_command(ctx, subcommand)
- # What is this, the tool lied about a command. Ignore it
- if cmd is None:
- continue
- if cmd.hidden:
- continue
-
- commands.append((subcommand, cmd))
-
- # allow for 3 times the default spacing
- if len(commands):
- limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands)
-
- rows = []
- for subcommand, cmd in commands:
- help = cmd.get_short_help_str(limit)
- rows.append((subcommand, help))
-
- if rows:
- with formatter.section(_("Commands")):
- formatter.write_dl(rows)
-
- def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]:
- if not args and self.no_args_is_help and not ctx.resilient_parsing:
- echo(ctx.get_help(), color=ctx.color)
- ctx.exit()
-
- rest = super().parse_args(ctx, args)
-
- if self.chain:
- ctx.protected_args = rest
- ctx.args = []
- elif rest:
- ctx.protected_args, ctx.args = rest[:1], rest[1:]
-
- return ctx.args
-
- def invoke(self, ctx: Context) -> t.Any:
- def _process_result(value: t.Any) -> t.Any:
- if self._result_callback is not None:
- value = ctx.invoke(self._result_callback, value, **ctx.params)
- return value
-
- if not ctx.protected_args:
- if self.invoke_without_command:
- # No subcommand was invoked, so the result callback is
- # invoked with None for regular groups, or an empty list
- # for chained groups.
- with ctx:
- super().invoke(ctx)
- return _process_result([] if self.chain else None)
- ctx.fail(_("Missing command."))
-
- # Fetch args back out
- args = [*ctx.protected_args, *ctx.args]
- ctx.args = []
- ctx.protected_args = []
-
- # If we're not in chain mode, we only allow the invocation of a
- # single command but we also inform the current context about the
- # name of the command to invoke.
- if not self.chain:
- # Make sure the context is entered so we do not clean up
- # resources until the result processor has worked.
- with ctx:
- cmd_name, cmd, args = self.resolve_command(ctx, args)
- assert cmd is not None
- ctx.invoked_subcommand = cmd_name
- super().invoke(ctx)
- sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)
- with sub_ctx:
- return _process_result(sub_ctx.command.invoke(sub_ctx))
-
- # In chain mode we create the contexts step by step, but after the
- # base command has been invoked. Because at that point we do not
- # know the subcommands yet, the invoked subcommand attribute is
- # set to ``*`` to inform the command that subcommands are executed
- # but nothing else.
- with ctx:
- ctx.invoked_subcommand = "*" if args else None
- super().invoke(ctx)
-
- # Otherwise we make every single context and invoke them in a
- # chain. In that case the return value to the result processor
- # is the list of all invoked subcommand's results.
- contexts = []
- while args:
- cmd_name, cmd, args = self.resolve_command(ctx, args)
- assert cmd is not None
- sub_ctx = cmd.make_context(
- cmd_name,
- args,
- parent=ctx,
- allow_extra_args=True,
- allow_interspersed_args=False,
- )
- contexts.append(sub_ctx)
- args, sub_ctx.args = sub_ctx.args, []
-
- rv = []
- for sub_ctx in contexts:
- with sub_ctx:
- rv.append(sub_ctx.command.invoke(sub_ctx))
- return _process_result(rv)
-
- def resolve_command(
- self, ctx: Context, args: t.List[str]
- ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]:
- cmd_name = make_str(args[0])
- original_cmd_name = cmd_name
-
- # Get the command
- cmd = self.get_command(ctx, cmd_name)
-
- # If we can't find the command but there is a normalization
- # function available, we try with that one.
- if cmd is None and ctx.token_normalize_func is not None:
- cmd_name = ctx.token_normalize_func(cmd_name)
- cmd = self.get_command(ctx, cmd_name)
-
- # If we don't find the command we want to show an error message
- # to the user that it was not provided. However, there is
- # something else we should do: if the first argument looks like
- # an option we want to kick off parsing again for arguments to
- # resolve things like --help which now should go to the main
- # place.
- if cmd is None and not ctx.resilient_parsing:
- if split_opt(cmd_name)[0]:
- self.parse_args(ctx, ctx.args)
- ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name))
- return cmd_name if cmd else None, cmd, args[1:]
-
- def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]:
- """Given a context and a command name, this returns a
- :class:`Command` object if it exists or returns `None`.
- """
- raise NotImplementedError
-
- def list_commands(self, ctx: Context) -> t.List[str]:
- """Returns a list of subcommand names in the order they should
- appear.
- """
- return []
-
- def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
- """Return a list of completions for the incomplete value. Looks
- at the names of options, subcommands, and chained
- multi-commands.
-
- :param ctx: Invocation context for this command.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- from click.shell_completion import CompletionItem
-
- results = [
- CompletionItem(name, help=command.get_short_help_str())
- for name, command in _complete_visible_commands(ctx, incomplete)
- ]
- results.extend(super().shell_complete(ctx, incomplete))
- return results
-
-
-class Group(MultiCommand):
- """A group allows a command to have subcommands attached. This is
- the most common way to implement nesting in Click.
-
- :param name: The name of the group command.
- :param commands: A dict mapping names to :class:`Command` objects.
- Can also be a list of :class:`Command`, which will use
- :attr:`Command.name` to create the dict.
- :param attrs: Other command arguments described in
- :class:`MultiCommand`, :class:`Command`, and
- :class:`BaseCommand`.
-
- .. versionchanged:: 8.0
- The ``commmands`` argument can be a list of command objects.
- """
-
- #: If set, this is used by the group's :meth:`command` decorator
- #: as the default :class:`Command` class. This is useful to make all
- #: subcommands use a custom command class.
- #:
- #: .. versionadded:: 8.0
- command_class: t.Optional[t.Type[Command]] = None
-
- #: If set, this is used by the group's :meth:`group` decorator
- #: as the default :class:`Group` class. This is useful to make all
- #: subgroups use a custom group class.
- #:
- #: If set to the special value :class:`type` (literally
- #: ``group_class = type``), this group's class will be used as the
- #: default class. This makes a custom group class continue to make
- #: custom groups.
- #:
- #: .. versionadded:: 8.0
- group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None
- # Literal[type] isn't valid, so use Type[type]
-
- def __init__(
- self,
- name: t.Optional[str] = None,
- commands: t.Optional[t.Union[t.Dict[str, Command], t.Sequence[Command]]] = None,
- **attrs: t.Any,
- ) -> None:
- super().__init__(name, **attrs)
-
- if commands is None:
- commands = {}
- elif isinstance(commands, abc.Sequence):
- commands = {c.name: c for c in commands if c.name is not None}
-
- #: The registered subcommands by their exported names.
- self.commands: t.Dict[str, Command] = commands
-
- def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None:
- """Registers another :class:`Command` with this group. If the name
- is not provided, the name of the command is used.
- """
- name = name or cmd.name
- if name is None:
- raise TypeError("Command has no name.")
- _check_multicommand(self, name, cmd, register=True)
- self.commands[name] = cmd
-
- def command(
- self, *args: t.Any, **kwargs: t.Any
- ) -> t.Callable[[t.Callable[..., t.Any]], Command]:
- """A shortcut decorator for declaring and attaching a command to
- the group. This takes the same arguments as :func:`command` and
- immediately registers the created command with this group by
- calling :meth:`add_command`.
-
- To customize the command class used, set the
- :attr:`command_class` attribute.
-
- .. versionchanged:: 8.0
- Added the :attr:`command_class` attribute.
- """
- from .decorators import command
-
- if self.command_class is not None and "cls" not in kwargs:
- kwargs["cls"] = self.command_class
-
- def decorator(f: t.Callable[..., t.Any]) -> Command:
- cmd = command(*args, **kwargs)(f)
- self.add_command(cmd)
- return cmd
-
- return decorator
-
- def group(
- self, *args: t.Any, **kwargs: t.Any
- ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]:
- """A shortcut decorator for declaring and attaching a group to
- the group. This takes the same arguments as :func:`group` and
- immediately registers the created group with this group by
- calling :meth:`add_command`.
-
- To customize the group class used, set the :attr:`group_class`
- attribute.
-
- .. versionchanged:: 8.0
- Added the :attr:`group_class` attribute.
- """
- from .decorators import group
-
- if self.group_class is not None and "cls" not in kwargs:
- if self.group_class is type:
- kwargs["cls"] = type(self)
- else:
- kwargs["cls"] = self.group_class
-
- def decorator(f: t.Callable[..., t.Any]) -> "Group":
- cmd = group(*args, **kwargs)(f)
- self.add_command(cmd)
- return cmd
-
- return decorator
-
- def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]:
- return self.commands.get(cmd_name)
-
- def list_commands(self, ctx: Context) -> t.List[str]:
- return sorted(self.commands)
-
-
-class CommandCollection(MultiCommand):
- """A command collection is a multi command that merges multiple multi
- commands together into one. This is a straightforward implementation
- that accepts a list of different multi commands as sources and
- provides all the commands for each of them.
- """
-
- def __init__(
- self,
- name: t.Optional[str] = None,
- sources: t.Optional[t.List[MultiCommand]] = None,
- **attrs: t.Any,
- ) -> None:
- super().__init__(name, **attrs)
- #: The list of registered multi commands.
- self.sources: t.List[MultiCommand] = sources or []
-
- def add_source(self, multi_cmd: MultiCommand) -> None:
- """Adds a new multi command to the chain dispatcher."""
- self.sources.append(multi_cmd)
-
- def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]:
- for source in self.sources:
- rv = source.get_command(ctx, cmd_name)
-
- if rv is not None:
- if self.chain:
- _check_multicommand(self, cmd_name, rv)
-
- return rv
-
- return None
-
- def list_commands(self, ctx: Context) -> t.List[str]:
- rv: t.Set[str] = set()
-
- for source in self.sources:
- rv.update(source.list_commands(ctx))
-
- return sorted(rv)
-
-
-def _check_iter(value: t.Any) -> t.Iterator[t.Any]:
- """Check if the value is iterable but not a string. Raises a type
- error, or return an iterator over the value.
- """
- if isinstance(value, str):
- raise TypeError
-
- return iter(value)
-
-
-class Parameter:
- r"""A parameter to a command comes in two versions: they are either
- :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently
- not supported by design as some of the internals for parsing are
- intentionally not finalized.
-
- Some settings are supported by both options and arguments.
-
- :param param_decls: the parameter declarations for this option or
- argument. This is a list of flags or argument
- names.
- :param type: the type that should be used. Either a :class:`ParamType`
- or a Python type. The later is converted into the former
- automatically if supported.
- :param required: controls if this is optional or not.
- :param default: the default value if omitted. This can also be a callable,
- in which case it's invoked when the default is needed
- without any arguments.
- :param callback: A function to further process or validate the value
- after type conversion. It is called as ``f(ctx, param, value)``
- and must return the value. It is called for all sources,
- including prompts.
- :param nargs: the number of arguments to match. If not ``1`` the return
- value is a tuple instead of single value. The default for
- nargs is ``1`` (except if the type is a tuple, then it's
- the arity of the tuple). If ``nargs=-1``, all remaining
- parameters are collected.
- :param metavar: how the value is represented in the help page.
- :param expose_value: if this is `True` then the value is passed onwards
- to the command callback and stored on the context,
- otherwise it's skipped.
- :param is_eager: eager values are processed before non eager ones. This
- should not be set for arguments or it will inverse the
- order of processing.
- :param envvar: a string or list of strings that are environment variables
- that should be checked.
- :param shell_complete: A function that returns custom shell
- completions. Used instead of the param's type completion if
- given. Takes ``ctx, param, incomplete`` and must return a list
- of :class:`~click.shell_completion.CompletionItem` or a list of
- strings.
-
- .. versionchanged:: 8.0
- ``process_value`` validates required parameters and bounded
- ``nargs``, and invokes the parameter callback before returning
- the value. This allows the callback to validate prompts.
- ``full_process_value`` is removed.
-
- .. versionchanged:: 8.0
- ``autocompletion`` is renamed to ``shell_complete`` and has new
- semantics described above. The old name is deprecated and will
- be removed in 8.1, until then it will be wrapped to match the
- new requirements.
-
- .. versionchanged:: 8.0
- For ``multiple=True, nargs>1``, the default must be a list of
- tuples.
-
- .. versionchanged:: 8.0
- Setting a default is no longer required for ``nargs>1``, it will
- default to ``None``. ``multiple=True`` or ``nargs=-1`` will
- default to ``()``.
-
- .. versionchanged:: 7.1
- Empty environment variables are ignored rather than taking the
- empty string value. This makes it possible for scripts to clear
- variables if they can't unset them.
-
- .. versionchanged:: 2.0
- Changed signature for parameter callback to also be passed the
- parameter. The old callback format will still work, but it will
- raise a warning to give you a chance to migrate the code easier.
- """
-
- param_type_name = "parameter"
-
- def __init__(
- self,
- param_decls: t.Optional[t.Sequence[str]] = None,
- type: t.Optional[t.Union[types.ParamType, t.Any]] = None,
- required: bool = False,
- default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None,
- callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None,
- nargs: t.Optional[int] = None,
- multiple: bool = False,
- metavar: t.Optional[str] = None,
- expose_value: bool = True,
- is_eager: bool = False,
- envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None,
- shell_complete: t.Optional[
- t.Callable[
- [Context, "Parameter", str],
- t.Union[t.List["CompletionItem"], t.List[str]],
- ]
- ] = None,
- autocompletion: t.Optional[
- t.Callable[
- [Context, t.List[str], str], t.List[t.Union[t.Tuple[str, str], str]]
- ]
- ] = None,
- ) -> None:
- self.name, self.opts, self.secondary_opts = self._parse_decls(
- param_decls or (), expose_value
- )
- self.type = types.convert_type(type, default)
-
- # Default nargs to what the type tells us if we have that
- # information available.
- if nargs is None:
- if self.type.is_composite:
- nargs = self.type.arity
- else:
- nargs = 1
-
- self.required = required
- self.callback = callback
- self.nargs = nargs
- self.multiple = multiple
- self.expose_value = expose_value
- self.default = default
- self.is_eager = is_eager
- self.metavar = metavar
- self.envvar = envvar
-
- if autocompletion is not None:
- import warnings
-
- warnings.warn(
- "'autocompletion' is renamed to 'shell_complete'. The old name is"
- " deprecated and will be removed in Click 8.1. See the docs about"
- " 'Parameter' for information about new behavior.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- def shell_complete(
- ctx: Context, param: "Parameter", incomplete: str
- ) -> t.List["CompletionItem"]:
- from click.shell_completion import CompletionItem
-
- out = []
-
- for c in autocompletion(ctx, [], incomplete): # type: ignore
- if isinstance(c, tuple):
- c = CompletionItem(c[0], help=c[1])
- elif isinstance(c, str):
- c = CompletionItem(c)
-
- if c.value.startswith(incomplete):
- out.append(c)
-
- return out
-
- self._custom_shell_complete = shell_complete
-
- if __debug__:
- if self.type.is_composite and nargs != self.type.arity:
- raise ValueError(
- f"'nargs' must be {self.type.arity} (or None) for"
- f" type {self.type!r}, but it was {nargs}."
- )
-
- # Skip no default or callable default.
- check_default = default if not callable(default) else None
-
- if check_default is not None:
- if multiple:
- try:
- # Only check the first value against nargs.
- check_default = next(_check_iter(check_default), None)
- except TypeError:
- raise ValueError(
- "'default' must be a list when 'multiple' is true."
- ) from None
-
- # Can be None for multiple with empty default.
- if nargs != 1 and check_default is not None:
- try:
- _check_iter(check_default)
- except TypeError:
- if multiple:
- message = (
- "'default' must be a list of lists when 'multiple' is"
- " true and 'nargs' != 1."
- )
- else:
- message = "'default' must be a list when 'nargs' != 1."
-
- raise ValueError(message) from None
-
- if nargs > 1 and len(check_default) != nargs:
- subject = "item length" if multiple else "length"
- raise ValueError(
- f"'default' {subject} must match nargs={nargs}."
- )
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- """Gather information that could be useful for a tool generating
- user-facing documentation.
-
- Use :meth:`click.Context.to_info_dict` to traverse the entire
- CLI structure.
-
- .. versionadded:: 8.0
- """
- return {
- "name": self.name,
- "param_type_name": self.param_type_name,
- "opts": self.opts,
- "secondary_opts": self.secondary_opts,
- "type": self.type.to_info_dict(),
- "required": self.required,
- "nargs": self.nargs,
- "multiple": self.multiple,
- "default": self.default,
- "envvar": self.envvar,
- }
-
- def __repr__(self) -> str:
- return f"<{self.__class__.__name__} {self.name}>"
-
- def _parse_decls(
- self, decls: t.Sequence[str], expose_value: bool
- ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]:
- raise NotImplementedError()
-
- @property
- def human_readable_name(self) -> str:
- """Returns the human readable name of this parameter. This is the
- same as the name for options, but the metavar for arguments.
- """
- return self.name # type: ignore
-
- def make_metavar(self) -> str:
- if self.metavar is not None:
- return self.metavar
-
- metavar = self.type.get_metavar(self)
-
- if metavar is None:
- metavar = self.type.name.upper()
-
- if self.nargs != 1:
- metavar += "..."
-
- return metavar
-
- @typing.overload
- def get_default(
- self, ctx: Context, call: "te.Literal[True]" = True
- ) -> t.Optional[t.Any]:
- ...
-
- @typing.overload
- def get_default(
- self, ctx: Context, call: bool = ...
- ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
- ...
-
- def get_default(
- self, ctx: Context, call: bool = True
- ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
- """Get the default for the parameter. Tries
- :meth:`Context.lookup_value` first, then the local default.
-
- :param ctx: Current context.
- :param call: If the default is a callable, call it. Disable to
- return the callable instead.
-
- .. versionchanged:: 8.0.1
- Type casting can fail in resilient parsing mode. Invalid
- defaults will not prevent showing help text.
-
- .. versionchanged:: 8.0
- Looks at ``ctx.default_map`` first.
-
- .. versionchanged:: 8.0
- Added the ``call`` parameter.
- """
- value = ctx.lookup_default(self.name, call=False) # type: ignore
-
- if value is None:
- value = self.default
-
- if callable(value):
- if not call:
- # Don't type cast the callable.
- return value
-
- value = value()
-
- try:
- return self.type_cast_value(ctx, value)
- except BadParameter:
- if ctx.resilient_parsing:
- return value
-
- raise
-
- def add_to_parser(self, parser: OptionParser, ctx: Context) -> None:
- raise NotImplementedError()
-
- def consume_value(
- self, ctx: Context, opts: t.Mapping[str, t.Any]
- ) -> t.Tuple[t.Any, ParameterSource]:
- value = opts.get(self.name) # type: ignore
- source = ParameterSource.COMMANDLINE
-
- if value is None:
- value = self.value_from_envvar(ctx)
- source = ParameterSource.ENVIRONMENT
-
- if value is None:
- value = ctx.lookup_default(self.name) # type: ignore
- source = ParameterSource.DEFAULT_MAP
-
- if value is None:
- value = self.get_default(ctx)
- source = ParameterSource.DEFAULT
-
- return value, source
-
- def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any:
- """Convert and validate a value against the option's
- :attr:`type`, :attr:`multiple`, and :attr:`nargs`.
- """
- if value is None:
- return () if self.multiple or self.nargs == -1 else None
-
- def check_iter(value: t.Any) -> t.Iterator:
- try:
- return _check_iter(value)
- except TypeError:
- # This should only happen when passing in args manually,
- # the parser should construct an iterable when parsing
- # the command line.
- raise BadParameter(
- _("Value must be an iterable."), ctx=ctx, param=self
- ) from None
-
- if self.nargs == 1 or self.type.is_composite:
- convert: t.Callable[[t.Any], t.Any] = partial(
- self.type, param=self, ctx=ctx
- )
- elif self.nargs == -1:
-
- def convert(value: t.Any) -> t.Tuple:
- return tuple(self.type(x, self, ctx) for x in check_iter(value))
-
- else: # nargs > 1
-
- def convert(value: t.Any) -> t.Tuple:
- value = tuple(check_iter(value))
-
- if len(value) != self.nargs:
- raise BadParameter(
- ngettext(
- "Takes {nargs} values but 1 was given.",
- "Takes {nargs} values but {len} were given.",
- len(value),
- ).format(nargs=self.nargs, len=len(value)),
- ctx=ctx,
- param=self,
- )
-
- return tuple(self.type(x, self, ctx) for x in value)
-
- if self.multiple:
- return tuple(convert(x) for x in check_iter(value))
-
- return convert(value)
-
- def value_is_missing(self, value: t.Any) -> bool:
- if value is None:
- return True
-
- if (self.nargs != 1 or self.multiple) and value == ():
- return True
-
- return False
-
- def process_value(self, ctx: Context, value: t.Any) -> t.Any:
- if value is not None:
- value = self.type_cast_value(ctx, value)
-
- if self.required and self.value_is_missing(value):
- raise MissingParameter(ctx=ctx, param=self)
-
- if self.callback is not None:
- value = self.callback(ctx, self, value)
-
- return value
-
- def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]:
- if self.envvar is None:
- return None
-
- if isinstance(self.envvar, str):
- rv = os.environ.get(self.envvar)
-
- if rv:
- return rv
- else:
- for envvar in self.envvar:
- rv = os.environ.get(envvar)
-
- if rv:
- return rv
-
- return None
-
- def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]:
- rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx)
-
- if rv is not None and self.nargs != 1:
- rv = self.type.split_envvar_value(rv)
-
- return rv
-
- def handle_parse_result(
- self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str]
- ) -> t.Tuple[t.Any, t.List[str]]:
- with augment_usage_errors(ctx, param=self):
- value, source = self.consume_value(ctx, opts)
- ctx.set_parameter_source(self.name, source) # type: ignore
-
- try:
- value = self.process_value(ctx, value)
- except Exception:
- if not ctx.resilient_parsing:
- raise
-
- value = None
-
- if self.expose_value:
- ctx.params[self.name] = value # type: ignore
-
- return value, args
-
- def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]:
- pass
-
- def get_usage_pieces(self, ctx: Context) -> t.List[str]:
- return []
-
- def get_error_hint(self, ctx: Context) -> str:
- """Get a stringified version of the param for use in error messages to
- indicate which param caused the error.
- """
- hint_list = self.opts or [self.human_readable_name]
- return " / ".join(f"'{x}'" for x in hint_list)
-
- def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
- """Return a list of completions for the incomplete value. If a
- ``shell_complete`` function was given during init, it is used.
- Otherwise, the :attr:`type`
- :meth:`~click.types.ParamType.shell_complete` function is used.
-
- :param ctx: Invocation context for this command.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- if self._custom_shell_complete is not None:
- results = self._custom_shell_complete(ctx, self, incomplete)
-
- if results and isinstance(results[0], str):
- from click.shell_completion import CompletionItem
-
- results = [CompletionItem(c) for c in results]
-
- return t.cast(t.List["CompletionItem"], results)
-
- return self.type.shell_complete(ctx, self, incomplete)
-
-
-class Option(Parameter):
- """Options are usually optional values on the command line and
- have some extra features that arguments don't have.
-
- All other parameters are passed onwards to the parameter constructor.
-
- :param show_default: controls if the default value should be shown on the
- help page. Normally, defaults are not shown. If this
- value is a string, it shows the string instead of the
- value. This is particularly useful for dynamic options.
- :param show_envvar: controls if an environment variable should be shown on
- the help page. Normally, environment variables
- are not shown.
- :param prompt: if set to `True` or a non empty string then the user will be
- prompted for input. If set to `True` the prompt will be the
- option name capitalized.
- :param confirmation_prompt: Prompt a second time to confirm the
- value if it was prompted for. Can be set to a string instead of
- ``True`` to customize the message.
- :param prompt_required: If set to ``False``, the user will be
- prompted for input only when the option was specified as a flag
- without a value.
- :param hide_input: if this is `True` then the input on the prompt will be
- hidden from the user. This is useful for password
- input.
- :param is_flag: forces this option to act as a flag. The default is
- auto detection.
- :param flag_value: which value should be used for this flag if it's
- enabled. This is set to a boolean automatically if
- the option string contains a slash to mark two options.
- :param multiple: if this is set to `True` then the argument is accepted
- multiple times and recorded. This is similar to ``nargs``
- in how it works but supports arbitrary number of
- arguments.
- :param count: this flag makes an option increment an integer.
- :param allow_from_autoenv: if this is enabled then the value of this
- parameter will be pulled from an environment
- variable in case a prefix is defined on the
- context.
- :param help: the help string.
- :param hidden: hide this option from help outputs.
-
- .. versionchanged:: 8.0.1
- ``type`` is detected from ``flag_value`` if given.
- """
-
- param_type_name = "option"
-
- def __init__(
- self,
- param_decls: t.Optional[t.Sequence[str]] = None,
- show_default: bool = False,
- prompt: t.Union[bool, str] = False,
- confirmation_prompt: t.Union[bool, str] = False,
- prompt_required: bool = True,
- hide_input: bool = False,
- is_flag: t.Optional[bool] = None,
- flag_value: t.Optional[t.Any] = None,
- multiple: bool = False,
- count: bool = False,
- allow_from_autoenv: bool = True,
- type: t.Optional[t.Union[types.ParamType, t.Any]] = None,
- help: t.Optional[str] = None,
- hidden: bool = False,
- show_choices: bool = True,
- show_envvar: bool = False,
- **attrs: t.Any,
- ) -> None:
- default_is_missing = "default" not in attrs
- super().__init__(param_decls, type=type, multiple=multiple, **attrs)
-
- if prompt is True:
- if self.name is None:
- raise TypeError("'name' is required with 'prompt=True'.")
-
- prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize()
- elif prompt is False:
- prompt_text = None
- else:
- prompt_text = t.cast(str, prompt)
-
- self.prompt = prompt_text
- self.confirmation_prompt = confirmation_prompt
- self.prompt_required = prompt_required
- self.hide_input = hide_input
- self.hidden = hidden
-
- # If prompt is enabled but not required, then the option can be
- # used as a flag to indicate using prompt or flag_value.
- self._flag_needs_value = self.prompt is not None and not self.prompt_required
-
- if is_flag is None:
- if flag_value is not None:
- # Implicitly a flag because flag_value was set.
- is_flag = True
- elif self._flag_needs_value:
- # Not a flag, but when used as a flag it shows a prompt.
- is_flag = False
- else:
- # Implicitly a flag because flag options were given.
- is_flag = bool(self.secondary_opts)
- elif is_flag is False and not self._flag_needs_value:
- # Not a flag, and prompt is not enabled, can be used as a
- # flag if flag_value is set.
- self._flag_needs_value = flag_value is not None
-
- if is_flag and default_is_missing:
- self.default: t.Union[t.Any, t.Callable[[], t.Any]] = False
-
- if flag_value is None:
- flag_value = not self.default
-
- if is_flag and type is None:
- # Re-guess the type from the flag value instead of the
- # default.
- self.type = types.convert_type(None, flag_value)
-
- self.is_flag: bool = is_flag
- self.is_bool_flag = isinstance(self.type, types.BoolParamType)
- self.flag_value: t.Any = flag_value
-
- # Counting
- self.count = count
- if count:
- if type is None:
- self.type = types.IntRange(min=0)
- if default_is_missing:
- self.default = 0
-
- self.allow_from_autoenv = allow_from_autoenv
- self.help = help
- self.show_default = show_default
- self.show_choices = show_choices
- self.show_envvar = show_envvar
-
- if __debug__:
- if self.nargs == -1:
- raise TypeError("nargs=-1 is not supported for options.")
-
- if self.prompt and self.is_flag and not self.is_bool_flag:
- raise TypeError("'prompt' is not valid for non-boolean flag.")
-
- if not self.is_bool_flag and self.secondary_opts:
- raise TypeError("Secondary flag is not valid for non-boolean flag.")
-
- if self.is_bool_flag and self.hide_input and self.prompt is not None:
- raise TypeError(
- "'prompt' with 'hide_input' is not valid for boolean flag."
- )
-
- if self.count:
- if self.multiple:
- raise TypeError("'count' is not valid with 'multiple'.")
-
- if self.is_flag:
- raise TypeError("'count' is not valid with 'is_flag'.")
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict.update(
- help=self.help,
- prompt=self.prompt,
- is_flag=self.is_flag,
- flag_value=self.flag_value,
- count=self.count,
- hidden=self.hidden,
- )
- return info_dict
-
- def _parse_decls(
- self, decls: t.Sequence[str], expose_value: bool
- ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]:
- opts = []
- secondary_opts = []
- name = None
- possible_names = []
-
- for decl in decls:
- if decl.isidentifier():
- if name is not None:
- raise TypeError("Name defined twice")
- name = decl
- else:
- split_char = ";" if decl[:1] == "/" else "/"
- if split_char in decl:
- first, second = decl.split(split_char, 1)
- first = first.rstrip()
- if first:
- possible_names.append(split_opt(first))
- opts.append(first)
- second = second.lstrip()
- if second:
- secondary_opts.append(second.lstrip())
- if first == second:
- raise ValueError(
- f"Boolean option {decl!r} cannot use the"
- " same flag for true/false."
- )
- else:
- possible_names.append(split_opt(decl))
- opts.append(decl)
-
- if name is None and possible_names:
- possible_names.sort(key=lambda x: -len(x[0])) # group long options first
- name = possible_names[0][1].replace("-", "_").lower()
- if not name.isidentifier():
- name = None
-
- if name is None:
- if not expose_value:
- return None, opts, secondary_opts
- raise TypeError("Could not determine name for option")
-
- if not opts and not secondary_opts:
- raise TypeError(
- f"No options defined but a name was passed ({name})."
- " Did you mean to declare an argument instead? Did"
- f" you mean to pass '--{name}'?"
- )
-
- return name, opts, secondary_opts
-
- def add_to_parser(self, parser: OptionParser, ctx: Context) -> None:
- if self.multiple:
- action = "append"
- elif self.count:
- action = "count"
- else:
- action = "store"
-
- if self.is_flag:
- action = f"{action}_const"
-
- if self.is_bool_flag and self.secondary_opts:
- parser.add_option(
- obj=self, opts=self.opts, dest=self.name, action=action, const=True
- )
- parser.add_option(
- obj=self,
- opts=self.secondary_opts,
- dest=self.name,
- action=action,
- const=False,
- )
- else:
- parser.add_option(
- obj=self,
- opts=self.opts,
- dest=self.name,
- action=action,
- const=self.flag_value,
- )
- else:
- parser.add_option(
- obj=self,
- opts=self.opts,
- dest=self.name,
- action=action,
- nargs=self.nargs,
- )
-
- def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]:
- if self.hidden:
- return None
-
- any_prefix_is_slash = False
-
- def _write_opts(opts: t.Sequence[str]) -> str:
- nonlocal any_prefix_is_slash
-
- rv, any_slashes = join_options(opts)
-
- if any_slashes:
- any_prefix_is_slash = True
-
- if not self.is_flag and not self.count:
- rv += f" {self.make_metavar()}"
-
- return rv
-
- rv = [_write_opts(self.opts)]
-
- if self.secondary_opts:
- rv.append(_write_opts(self.secondary_opts))
-
- help = self.help or ""
- extra = []
-
- if self.show_envvar:
- envvar = self.envvar
-
- if envvar is None:
- if (
- self.allow_from_autoenv
- and ctx.auto_envvar_prefix is not None
- and self.name is not None
- ):
- envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}"
-
- if envvar is not None:
- var_str = (
- envvar
- if isinstance(envvar, str)
- else ", ".join(str(d) for d in envvar)
- )
- extra.append(_("env var: {var}").format(var=var_str))
-
- # Temporarily enable resilient parsing to avoid type casting
- # failing for the default. Might be possible to extend this to
- # help formatting in general.
- resilient = ctx.resilient_parsing
- ctx.resilient_parsing = True
-
- try:
- default_value = self.get_default(ctx, call=False)
- finally:
- ctx.resilient_parsing = resilient
-
- show_default_is_str = isinstance(self.show_default, str)
-
- if show_default_is_str or (
- default_value is not None and (self.show_default or ctx.show_default)
- ):
- if show_default_is_str:
- default_string = f"({self.show_default})"
- elif isinstance(default_value, (list, tuple)):
- default_string = ", ".join(str(d) for d in default_value)
- elif callable(default_value):
- default_string = _("(dynamic)")
- elif self.is_bool_flag and self.secondary_opts:
- # For boolean flags that have distinct True/False opts,
- # use the opt without prefix instead of the value.
- default_string = split_opt(
- (self.opts if self.default else self.secondary_opts)[0]
- )[1]
- else:
- default_string = str(default_value)
-
- extra.append(_("default: {default}").format(default=default_string))
-
- if isinstance(self.type, types._NumberRangeBase):
- range_str = self.type._describe_range()
-
- if range_str:
- extra.append(range_str)
-
- if self.required:
- extra.append(_("required"))
-
- if extra:
- extra_str = ";".join(extra)
- help = f"{help} [{extra_str}]" if help else f"[{extra_str}]"
-
- return ("; " if any_prefix_is_slash else " / ").join(rv), help
-
- @typing.overload
- def get_default(
- self, ctx: Context, call: "te.Literal[True]" = True
- ) -> t.Optional[t.Any]:
- ...
-
- @typing.overload
- def get_default(
- self, ctx: Context, call: bool = ...
- ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
- ...
-
- def get_default(
- self, ctx: Context, call: bool = True
- ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
- # If we're a non boolean flag our default is more complex because
- # we need to look at all flags in the same group to figure out
- # if we're the the default one in which case we return the flag
- # value as default.
- if self.is_flag and not self.is_bool_flag:
- for param in ctx.command.params:
- if param.name == self.name and param.default:
- return param.flag_value # type: ignore
-
- return None
-
- return super().get_default(ctx, call=call)
-
- def prompt_for_value(self, ctx: Context) -> t.Any:
- """This is an alternative flow that can be activated in the full
- value processing if a value does not exist. It will prompt the
- user until a valid value exists and then returns the processed
- value as result.
- """
- assert self.prompt is not None
-
- # Calculate the default before prompting anything to be stable.
- default = self.get_default(ctx)
-
- # If this is a prompt for a flag we need to handle this
- # differently.
- if self.is_bool_flag:
- return confirm(self.prompt, default)
-
- return prompt(
- self.prompt,
- default=default,
- type=self.type,
- hide_input=self.hide_input,
- show_choices=self.show_choices,
- confirmation_prompt=self.confirmation_prompt,
- value_proc=lambda x: self.process_value(ctx, x),
- )
-
- def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]:
- rv = super().resolve_envvar_value(ctx)
-
- if rv is not None:
- return rv
-
- if (
- self.allow_from_autoenv
- and ctx.auto_envvar_prefix is not None
- and self.name is not None
- ):
- envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}"
- rv = os.environ.get(envvar)
-
- return rv
-
- def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]:
- rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx)
-
- if rv is None:
- return None
-
- value_depth = (self.nargs != 1) + bool(self.multiple)
-
- if value_depth > 0:
- rv = self.type.split_envvar_value(rv)
-
- if self.multiple and self.nargs != 1:
- rv = batch(rv, self.nargs)
-
- return rv
-
- def consume_value(
- self, ctx: Context, opts: t.Mapping[str, "Parameter"]
- ) -> t.Tuple[t.Any, ParameterSource]:
- value, source = super().consume_value(ctx, opts)
-
- # The parser will emit a sentinel value if the option can be
- # given as a flag without a value. This is different from None
- # to distinguish from the flag not being given at all.
- if value is _flag_needs_value:
- if self.prompt is not None and not ctx.resilient_parsing:
- value = self.prompt_for_value(ctx)
- source = ParameterSource.PROMPT
- else:
- value = self.flag_value
- source = ParameterSource.COMMANDLINE
-
- # The value wasn't set, or used the param's default, prompt if
- # prompting is enabled.
- elif (
- source in {None, ParameterSource.DEFAULT}
- and self.prompt is not None
- and (self.required or self.prompt_required)
- and not ctx.resilient_parsing
- ):
- value = self.prompt_for_value(ctx)
- source = ParameterSource.PROMPT
-
- return value, source
-
-
-class Argument(Parameter):
- """Arguments are positional parameters to a command. They generally
- provide fewer features than options but can have infinite ``nargs``
- and are required by default.
-
- All parameters are passed onwards to the parameter constructor.
- """
-
- param_type_name = "argument"
-
- def __init__(
- self,
- param_decls: t.Sequence[str],
- required: t.Optional[bool] = None,
- **attrs: t.Any,
- ) -> None:
- if required is None:
- if attrs.get("default") is not None:
- required = False
- else:
- required = attrs.get("nargs", 1) > 0
-
- if "multiple" in attrs:
- raise TypeError("__init__() got an unexpected keyword argument 'multiple'.")
-
- super().__init__(param_decls, required=required, **attrs)
-
- if __debug__:
- if self.default is not None and self.nargs == -1:
- raise TypeError("'default' is not supported for nargs=-1.")
-
- @property
- def human_readable_name(self) -> str:
- if self.metavar is not None:
- return self.metavar
- return self.name.upper() # type: ignore
-
- def make_metavar(self) -> str:
- if self.metavar is not None:
- return self.metavar
- var = self.type.get_metavar(self)
- if not var:
- var = self.name.upper() # type: ignore
- if not self.required:
- var = f"[{var}]"
- if self.nargs != 1:
- var += "..."
- return var
-
- def _parse_decls(
- self, decls: t.Sequence[str], expose_value: bool
- ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]:
- if not decls:
- if not expose_value:
- return None, [], []
- raise TypeError("Could not determine name for argument")
- if len(decls) == 1:
- name = arg = decls[0]
- name = name.replace("-", "_").lower()
- else:
- raise TypeError(
- "Arguments take exactly one parameter declaration, got"
- f" {len(decls)}."
- )
- return name, [arg], []
-
- def get_usage_pieces(self, ctx: Context) -> t.List[str]:
- return [self.make_metavar()]
-
- def get_error_hint(self, ctx: Context) -> str:
- return f"'{self.make_metavar()}'"
-
- def add_to_parser(self, parser: OptionParser, ctx: Context) -> None:
- parser.add_argument(dest=self.name, nargs=self.nargs, obj=self)
diff --git a/venv/lib/python3.9/site-packages/click/decorators.py b/venv/lib/python3.9/site-packages/click/decorators.py
deleted file mode 100644
index 5940e69..0000000
--- a/venv/lib/python3.9/site-packages/click/decorators.py
+++ /dev/null
@@ -1,437 +0,0 @@
-import inspect
-import types
-import typing as t
-from functools import update_wrapper
-from gettext import gettext as _
-
-from .core import Argument
-from .core import Command
-from .core import Context
-from .core import Group
-from .core import Option
-from .core import Parameter
-from .globals import get_current_context
-from .utils import echo
-
-F = t.TypeVar("F", bound=t.Callable[..., t.Any])
-FC = t.TypeVar("FC", t.Callable[..., t.Any], Command)
-
-
-def pass_context(f: F) -> F:
- """Marks a callback as wanting to receive the current context
- object as first argument.
- """
-
- def new_func(*args, **kwargs): # type: ignore
- return f(get_current_context(), *args, **kwargs)
-
- return update_wrapper(t.cast(F, new_func), f)
-
-
-def pass_obj(f: F) -> F:
- """Similar to :func:`pass_context`, but only pass the object on the
- context onwards (:attr:`Context.obj`). This is useful if that object
- represents the state of a nested system.
- """
-
- def new_func(*args, **kwargs): # type: ignore
- return f(get_current_context().obj, *args, **kwargs)
-
- return update_wrapper(t.cast(F, new_func), f)
-
-
-def make_pass_decorator(
- object_type: t.Type, ensure: bool = False
-) -> "t.Callable[[F], F]":
- """Given an object type this creates a decorator that will work
- similar to :func:`pass_obj` but instead of passing the object of the
- current context, it will find the innermost context of type
- :func:`object_type`.
-
- This generates a decorator that works roughly like this::
-
- from functools import update_wrapper
-
- def decorator(f):
- @pass_context
- def new_func(ctx, *args, **kwargs):
- obj = ctx.find_object(object_type)
- return ctx.invoke(f, obj, *args, **kwargs)
- return update_wrapper(new_func, f)
- return decorator
-
- :param object_type: the type of the object to pass.
- :param ensure: if set to `True`, a new object will be created and
- remembered on the context if it's not there yet.
- """
-
- def decorator(f: F) -> F:
- def new_func(*args, **kwargs): # type: ignore
- ctx = get_current_context()
-
- if ensure:
- obj = ctx.ensure_object(object_type)
- else:
- obj = ctx.find_object(object_type)
-
- if obj is None:
- raise RuntimeError(
- "Managed to invoke callback without a context"
- f" object of type {object_type.__name__!r}"
- " existing."
- )
-
- return ctx.invoke(f, obj, *args, **kwargs)
-
- return update_wrapper(t.cast(F, new_func), f)
-
- return decorator
-
-
-def pass_meta_key(
- key: str, *, doc_description: t.Optional[str] = None
-) -> "t.Callable[[F], F]":
- """Create a decorator that passes a key from
- :attr:`click.Context.meta` as the first argument to the decorated
- function.
-
- :param key: Key in ``Context.meta`` to pass.
- :param doc_description: Description of the object being passed,
- inserted into the decorator's docstring. Defaults to "the 'key'
- key from Context.meta".
-
- .. versionadded:: 8.0
- """
-
- def decorator(f: F) -> F:
- def new_func(*args, **kwargs): # type: ignore
- ctx = get_current_context()
- obj = ctx.meta[key]
- return ctx.invoke(f, obj, *args, **kwargs)
-
- return update_wrapper(t.cast(F, new_func), f)
-
- if doc_description is None:
- doc_description = f"the {key!r} key from :attr:`click.Context.meta`"
-
- decorator.__doc__ = (
- f"Decorator that passes {doc_description} as the first argument"
- " to the decorated function."
- )
- return decorator
-
-
-def _make_command(
- f: F,
- name: t.Optional[str],
- attrs: t.MutableMapping[str, t.Any],
- cls: t.Type[Command],
-) -> Command:
- if isinstance(f, Command):
- raise TypeError("Attempted to convert a callback into a command twice.")
-
- try:
- params = f.__click_params__ # type: ignore
- params.reverse()
- del f.__click_params__ # type: ignore
- except AttributeError:
- params = []
-
- help = attrs.get("help")
-
- if help is None:
- help = inspect.getdoc(f)
- else:
- help = inspect.cleandoc(help)
-
- attrs["help"] = help
- return cls(
- name=name or f.__name__.lower().replace("_", "-"),
- callback=f,
- params=params,
- **attrs,
- )
-
-
-def command(
- name: t.Optional[str] = None,
- cls: t.Optional[t.Type[Command]] = None,
- **attrs: t.Any,
-) -> t.Callable[[F], Command]:
- r"""Creates a new :class:`Command` and uses the decorated function as
- callback. This will also automatically attach all decorated
- :func:`option`\s and :func:`argument`\s as parameters to the command.
-
- The name of the command defaults to the name of the function with
- underscores replaced by dashes. If you want to change that, you can
- pass the intended name as the first argument.
-
- All keyword arguments are forwarded to the underlying command class.
-
- Once decorated the function turns into a :class:`Command` instance
- that can be invoked as a command line utility or be attached to a
- command :class:`Group`.
-
- :param name: the name of the command. This defaults to the function
- name with underscores replaced by dashes.
- :param cls: the command class to instantiate. This defaults to
- :class:`Command`.
- """
- if cls is None:
- cls = Command
-
- def decorator(f: t.Callable[..., t.Any]) -> Command:
- cmd = _make_command(f, name, attrs, cls) # type: ignore
- cmd.__doc__ = f.__doc__
- return cmd
-
- return decorator
-
-
-def group(name: t.Optional[str] = None, **attrs: t.Any) -> t.Callable[[F], Group]:
- """Creates a new :class:`Group` with a function as callback. This
- works otherwise the same as :func:`command` just that the `cls`
- parameter is set to :class:`Group`.
- """
- attrs.setdefault("cls", Group)
- return t.cast(Group, command(name, **attrs))
-
-
-def _param_memo(f: FC, param: Parameter) -> None:
- if isinstance(f, Command):
- f.params.append(param)
- else:
- if not hasattr(f, "__click_params__"):
- f.__click_params__ = [] # type: ignore
-
- f.__click_params__.append(param) # type: ignore
-
-
-def argument(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]:
- """Attaches an argument to the command. All positional arguments are
- passed as parameter declarations to :class:`Argument`; all keyword
- arguments are forwarded unchanged (except ``cls``).
- This is equivalent to creating an :class:`Argument` instance manually
- and attaching it to the :attr:`Command.params` list.
-
- :param cls: the argument class to instantiate. This defaults to
- :class:`Argument`.
- """
-
- def decorator(f: FC) -> FC:
- ArgumentClass = attrs.pop("cls", Argument)
- _param_memo(f, ArgumentClass(param_decls, **attrs))
- return f
-
- return decorator
-
-
-def option(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]:
- """Attaches an option to the command. All positional arguments are
- passed as parameter declarations to :class:`Option`; all keyword
- arguments are forwarded unchanged (except ``cls``).
- This is equivalent to creating an :class:`Option` instance manually
- and attaching it to the :attr:`Command.params` list.
-
- :param cls: the option class to instantiate. This defaults to
- :class:`Option`.
- """
-
- def decorator(f: FC) -> FC:
- # Issue 926, copy attrs, so pre-defined options can re-use the same cls=
- option_attrs = attrs.copy()
-
- if "help" in option_attrs:
- option_attrs["help"] = inspect.cleandoc(option_attrs["help"])
- OptionClass = option_attrs.pop("cls", Option)
- _param_memo(f, OptionClass(param_decls, **option_attrs))
- return f
-
- return decorator
-
-
-def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]:
- """Add a ``--yes`` option which shows a prompt before continuing if
- not passed. If the prompt is declined, the program will exit.
-
- :param param_decls: One or more option names. Defaults to the single
- value ``"--yes"``.
- :param kwargs: Extra arguments are passed to :func:`option`.
- """
-
- def callback(ctx: Context, param: Parameter, value: bool) -> None:
- if not value:
- ctx.abort()
-
- if not param_decls:
- param_decls = ("--yes",)
-
- kwargs.setdefault("is_flag", True)
- kwargs.setdefault("callback", callback)
- kwargs.setdefault("expose_value", False)
- kwargs.setdefault("prompt", "Do you want to continue?")
- kwargs.setdefault("help", "Confirm the action without prompting.")
- return option(*param_decls, **kwargs)
-
-
-def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]:
- """Add a ``--password`` option which prompts for a password, hiding
- input and asking to enter the value again for confirmation.
-
- :param param_decls: One or more option names. Defaults to the single
- value ``"--password"``.
- :param kwargs: Extra arguments are passed to :func:`option`.
- """
- if not param_decls:
- param_decls = ("--password",)
-
- kwargs.setdefault("prompt", True)
- kwargs.setdefault("confirmation_prompt", True)
- kwargs.setdefault("hide_input", True)
- return option(*param_decls, **kwargs)
-
-
-def version_option(
- version: t.Optional[str] = None,
- *param_decls: str,
- package_name: t.Optional[str] = None,
- prog_name: t.Optional[str] = None,
- message: t.Optional[str] = None,
- **kwargs: t.Any,
-) -> t.Callable[[FC], FC]:
- """Add a ``--version`` option which immediately prints the version
- number and exits the program.
-
- If ``version`` is not provided, Click will try to detect it using
- :func:`importlib.metadata.version` to get the version for the
- ``package_name``. On Python < 3.8, the ``importlib_metadata``
- backport must be installed.
-
- If ``package_name`` is not provided, Click will try to detect it by
- inspecting the stack frames. This will be used to detect the
- version, so it must match the name of the installed package.
-
- :param version: The version number to show. If not provided, Click
- will try to detect it.
- :param param_decls: One or more option names. Defaults to the single
- value ``"--version"``.
- :param package_name: The package name to detect the version from. If
- not provided, Click will try to detect it.
- :param prog_name: The name of the CLI to show in the message. If not
- provided, it will be detected from the command.
- :param message: The message to show. The values ``%(prog)s``,
- ``%(package)s``, and ``%(version)s`` are available. Defaults to
- ``"%(prog)s, version %(version)s"``.
- :param kwargs: Extra arguments are passed to :func:`option`.
- :raise RuntimeError: ``version`` could not be detected.
-
- .. versionchanged:: 8.0
- Add the ``package_name`` parameter, and the ``%(package)s``
- value for messages.
-
- .. versionchanged:: 8.0
- Use :mod:`importlib.metadata` instead of ``pkg_resources``. The
- version is detected based on the package name, not the entry
- point name. The Python package name must match the installed
- package name, or be passed with ``package_name=``.
- """
- if message is None:
- message = _("%(prog)s, version %(version)s")
-
- if version is None and package_name is None:
- frame = inspect.currentframe()
- assert frame is not None
- assert frame.f_back is not None
- f_globals = frame.f_back.f_globals if frame is not None else None
- # break reference cycle
- # https://docs.python.org/3/library/inspect.html#the-interpreter-stack
- del frame
-
- if f_globals is not None:
- package_name = f_globals.get("__name__")
-
- if package_name == "__main__":
- package_name = f_globals.get("__package__")
-
- if package_name:
- package_name = package_name.partition(".")[0]
-
- def callback(ctx: Context, param: Parameter, value: bool) -> None:
- if not value or ctx.resilient_parsing:
- return
-
- nonlocal prog_name
- nonlocal version
-
- if prog_name is None:
- prog_name = ctx.find_root().info_name
-
- if version is None and package_name is not None:
- metadata: t.Optional[types.ModuleType]
-
- try:
- from importlib import metadata # type: ignore
- except ImportError:
- # Python < 3.8
- import importlib_metadata as metadata # type: ignore
-
- try:
- version = metadata.version(package_name) # type: ignore
- except metadata.PackageNotFoundError: # type: ignore
- raise RuntimeError(
- f"{package_name!r} is not installed. Try passing"
- " 'package_name' instead."
- )
-
- if version is None:
- raise RuntimeError(
- f"Could not determine the version for {package_name!r} automatically."
- )
-
- echo(
- t.cast(str, message)
- % {"prog": prog_name, "package": package_name, "version": version},
- color=ctx.color,
- )
- ctx.exit()
-
- if not param_decls:
- param_decls = ("--version",)
-
- kwargs.setdefault("is_flag", True)
- kwargs.setdefault("expose_value", False)
- kwargs.setdefault("is_eager", True)
- kwargs.setdefault("help", _("Show the version and exit."))
- kwargs["callback"] = callback
- return option(*param_decls, **kwargs)
-
-
-def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]:
- """Add a ``--help`` option which immediately prints the help page
- and exits the program.
-
- This is usually unnecessary, as the ``--help`` option is added to
- each command automatically unless ``add_help_option=False`` is
- passed.
-
- :param param_decls: One or more option names. Defaults to the single
- value ``"--help"``.
- :param kwargs: Extra arguments are passed to :func:`option`.
- """
-
- def callback(ctx: Context, param: Parameter, value: bool) -> None:
- if not value or ctx.resilient_parsing:
- return
-
- echo(ctx.get_help(), color=ctx.color)
- ctx.exit()
-
- if not param_decls:
- param_decls = ("--help",)
-
- kwargs.setdefault("is_flag", True)
- kwargs.setdefault("expose_value", False)
- kwargs.setdefault("is_eager", True)
- kwargs.setdefault("help", _("Show this message and exit."))
- kwargs["callback"] = callback
- return option(*param_decls, **kwargs)
diff --git a/venv/lib/python3.9/site-packages/click/exceptions.py b/venv/lib/python3.9/site-packages/click/exceptions.py
deleted file mode 100644
index 9e20b3e..0000000
--- a/venv/lib/python3.9/site-packages/click/exceptions.py
+++ /dev/null
@@ -1,287 +0,0 @@
-import os
-import typing as t
-from gettext import gettext as _
-from gettext import ngettext
-
-from ._compat import get_text_stderr
-from .utils import echo
-
-if t.TYPE_CHECKING:
- from .core import Context
- from .core import Parameter
-
-
-def _join_param_hints(
- param_hint: t.Optional[t.Union[t.Sequence[str], str]]
-) -> t.Optional[str]:
- if param_hint is not None and not isinstance(param_hint, str):
- return " / ".join(repr(x) for x in param_hint)
-
- return param_hint
-
-
-class ClickException(Exception):
- """An exception that Click can handle and show to the user."""
-
- #: The exit code for this exception.
- exit_code = 1
-
- def __init__(self, message: str) -> None:
- super().__init__(message)
- self.message = message
-
- def format_message(self) -> str:
- return self.message
-
- def __str__(self) -> str:
- return self.message
-
- def show(self, file: t.Optional[t.IO] = None) -> None:
- if file is None:
- file = get_text_stderr()
-
- echo(_("Error: {message}").format(message=self.format_message()), file=file)
-
-
-class UsageError(ClickException):
- """An internal exception that signals a usage error. This typically
- aborts any further handling.
-
- :param message: the error message to display.
- :param ctx: optionally the context that caused this error. Click will
- fill in the context automatically in some situations.
- """
-
- exit_code = 2
-
- def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None:
- super().__init__(message)
- self.ctx = ctx
- self.cmd = self.ctx.command if self.ctx else None
-
- def show(self, file: t.Optional[t.IO] = None) -> None:
- if file is None:
- file = get_text_stderr()
- color = None
- hint = ""
- if (
- self.ctx is not None
- and self.ctx.command.get_help_option(self.ctx) is not None
- ):
- hint = _("Try '{command} {option}' for help.").format(
- command=self.ctx.command_path, option=self.ctx.help_option_names[0]
- )
- hint = f"{hint}\n"
- if self.ctx is not None:
- color = self.ctx.color
- echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color)
- echo(
- _("Error: {message}").format(message=self.format_message()),
- file=file,
- color=color,
- )
-
-
-class BadParameter(UsageError):
- """An exception that formats out a standardized error message for a
- bad parameter. This is useful when thrown from a callback or type as
- Click will attach contextual information to it (for instance, which
- parameter it is).
-
- .. versionadded:: 2.0
-
- :param param: the parameter object that caused this error. This can
- be left out, and Click will attach this info itself
- if possible.
- :param param_hint: a string that shows up as parameter name. This
- can be used as alternative to `param` in cases
- where custom validation should happen. If it is
- a string it's used as such, if it's a list then
- each item is quoted and separated.
- """
-
- def __init__(
- self,
- message: str,
- ctx: t.Optional["Context"] = None,
- param: t.Optional["Parameter"] = None,
- param_hint: t.Optional[str] = None,
- ) -> None:
- super().__init__(message, ctx)
- self.param = param
- self.param_hint = param_hint
-
- def format_message(self) -> str:
- if self.param_hint is not None:
- param_hint = self.param_hint
- elif self.param is not None:
- param_hint = self.param.get_error_hint(self.ctx) # type: ignore
- else:
- return _("Invalid value: {message}").format(message=self.message)
-
- return _("Invalid value for {param_hint}: {message}").format(
- param_hint=_join_param_hints(param_hint), message=self.message
- )
-
-
-class MissingParameter(BadParameter):
- """Raised if click required an option or argument but it was not
- provided when invoking the script.
-
- .. versionadded:: 4.0
-
- :param param_type: a string that indicates the type of the parameter.
- The default is to inherit the parameter type from
- the given `param`. Valid values are ``'parameter'``,
- ``'option'`` or ``'argument'``.
- """
-
- def __init__(
- self,
- message: t.Optional[str] = None,
- ctx: t.Optional["Context"] = None,
- param: t.Optional["Parameter"] = None,
- param_hint: t.Optional[str] = None,
- param_type: t.Optional[str] = None,
- ) -> None:
- super().__init__(message or "", ctx, param, param_hint)
- self.param_type = param_type
-
- def format_message(self) -> str:
- if self.param_hint is not None:
- param_hint: t.Optional[str] = self.param_hint
- elif self.param is not None:
- param_hint = self.param.get_error_hint(self.ctx) # type: ignore
- else:
- param_hint = None
-
- param_hint = _join_param_hints(param_hint)
- param_hint = f" {param_hint}" if param_hint else ""
-
- param_type = self.param_type
- if param_type is None and self.param is not None:
- param_type = self.param.param_type_name
-
- msg = self.message
- if self.param is not None:
- msg_extra = self.param.type.get_missing_message(self.param)
- if msg_extra:
- if msg:
- msg += f". {msg_extra}"
- else:
- msg = msg_extra
-
- msg = f" {msg}" if msg else ""
-
- # Translate param_type for known types.
- if param_type == "argument":
- missing = _("Missing argument")
- elif param_type == "option":
- missing = _("Missing option")
- elif param_type == "parameter":
- missing = _("Missing parameter")
- else:
- missing = _("Missing {param_type}").format(param_type=param_type)
-
- return f"{missing}{param_hint}.{msg}"
-
- def __str__(self) -> str:
- if not self.message:
- param_name = self.param.name if self.param else None
- return _("Missing parameter: {param_name}").format(param_name=param_name)
- else:
- return self.message
-
-
-class NoSuchOption(UsageError):
- """Raised if click attempted to handle an option that does not
- exist.
-
- .. versionadded:: 4.0
- """
-
- def __init__(
- self,
- option_name: str,
- message: t.Optional[str] = None,
- possibilities: t.Optional[t.Sequence[str]] = None,
- ctx: t.Optional["Context"] = None,
- ) -> None:
- if message is None:
- message = _("No such option: {name}").format(name=option_name)
-
- super().__init__(message, ctx)
- self.option_name = option_name
- self.possibilities = possibilities
-
- def format_message(self) -> str:
- if not self.possibilities:
- return self.message
-
- possibility_str = ", ".join(sorted(self.possibilities))
- suggest = ngettext(
- "Did you mean {possibility}?",
- "(Possible options: {possibilities})",
- len(self.possibilities),
- ).format(possibility=possibility_str, possibilities=possibility_str)
- return f"{self.message} {suggest}"
-
-
-class BadOptionUsage(UsageError):
- """Raised if an option is generally supplied but the use of the option
- was incorrect. This is for instance raised if the number of arguments
- for an option is not correct.
-
- .. versionadded:: 4.0
-
- :param option_name: the name of the option being used incorrectly.
- """
-
- def __init__(
- self, option_name: str, message: str, ctx: t.Optional["Context"] = None
- ) -> None:
- super().__init__(message, ctx)
- self.option_name = option_name
-
-
-class BadArgumentUsage(UsageError):
- """Raised if an argument is generally supplied but the use of the argument
- was incorrect. This is for instance raised if the number of values
- for an argument is not correct.
-
- .. versionadded:: 6.0
- """
-
-
-class FileError(ClickException):
- """Raised if a file cannot be opened."""
-
- def __init__(self, filename: str, hint: t.Optional[str] = None) -> None:
- if hint is None:
- hint = _("unknown error")
-
- super().__init__(hint)
- self.ui_filename = os.fsdecode(filename)
- self.filename = filename
-
- def format_message(self) -> str:
- return _("Could not open file {filename!r}: {message}").format(
- filename=self.ui_filename, message=self.message
- )
-
-
-class Abort(RuntimeError):
- """An internal signalling exception that signals Click to abort."""
-
-
-class Exit(RuntimeError):
- """An exception that indicates that the application should exit with some
- status code.
-
- :param code: the status code to exit with.
- """
-
- __slots__ = ("exit_code",)
-
- def __init__(self, code: int = 0) -> None:
- self.exit_code = code
diff --git a/venv/lib/python3.9/site-packages/click/formatting.py b/venv/lib/python3.9/site-packages/click/formatting.py
deleted file mode 100644
index ddd2a2f..0000000
--- a/venv/lib/python3.9/site-packages/click/formatting.py
+++ /dev/null
@@ -1,301 +0,0 @@
-import typing as t
-from contextlib import contextmanager
-from gettext import gettext as _
-
-from ._compat import term_len
-from .parser import split_opt
-
-# Can force a width. This is used by the test system
-FORCED_WIDTH: t.Optional[int] = None
-
-
-def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]:
- widths: t.Dict[int, int] = {}
-
- for row in rows:
- for idx, col in enumerate(row):
- widths[idx] = max(widths.get(idx, 0), term_len(col))
-
- return tuple(y for x, y in sorted(widths.items()))
-
-
-def iter_rows(
- rows: t.Iterable[t.Tuple[str, str]], col_count: int
-) -> t.Iterator[t.Tuple[str, ...]]:
- for row in rows:
- yield row + ("",) * (col_count - len(row))
-
-
-def wrap_text(
- text: str,
- width: int = 78,
- initial_indent: str = "",
- subsequent_indent: str = "",
- preserve_paragraphs: bool = False,
-) -> str:
- """A helper function that intelligently wraps text. By default, it
- assumes that it operates on a single paragraph of text but if the
- `preserve_paragraphs` parameter is provided it will intelligently
- handle paragraphs (defined by two empty lines).
-
- If paragraphs are handled, a paragraph can be prefixed with an empty
- line containing the ``\\b`` character (``\\x08``) to indicate that
- no rewrapping should happen in that block.
-
- :param text: the text that should be rewrapped.
- :param width: the maximum width for the text.
- :param initial_indent: the initial indent that should be placed on the
- first line as a string.
- :param subsequent_indent: the indent string that should be placed on
- each consecutive line.
- :param preserve_paragraphs: if this flag is set then the wrapping will
- intelligently handle paragraphs.
- """
- from ._textwrap import TextWrapper
-
- text = text.expandtabs()
- wrapper = TextWrapper(
- width,
- initial_indent=initial_indent,
- subsequent_indent=subsequent_indent,
- replace_whitespace=False,
- )
- if not preserve_paragraphs:
- return wrapper.fill(text)
-
- p: t.List[t.Tuple[int, bool, str]] = []
- buf: t.List[str] = []
- indent = None
-
- def _flush_par() -> None:
- if not buf:
- return
- if buf[0].strip() == "\b":
- p.append((indent or 0, True, "\n".join(buf[1:])))
- else:
- p.append((indent or 0, False, " ".join(buf)))
- del buf[:]
-
- for line in text.splitlines():
- if not line:
- _flush_par()
- indent = None
- else:
- if indent is None:
- orig_len = term_len(line)
- line = line.lstrip()
- indent = orig_len - term_len(line)
- buf.append(line)
- _flush_par()
-
- rv = []
- for indent, raw, text in p:
- with wrapper.extra_indent(" " * indent):
- if raw:
- rv.append(wrapper.indent_only(text))
- else:
- rv.append(wrapper.fill(text))
-
- return "\n\n".join(rv)
-
-
-class HelpFormatter:
- """This class helps with formatting text-based help pages. It's
- usually just needed for very special internal cases, but it's also
- exposed so that developers can write their own fancy outputs.
-
- At present, it always writes into memory.
-
- :param indent_increment: the additional increment for each level.
- :param width: the width for the text. This defaults to the terminal
- width clamped to a maximum of 78.
- """
-
- def __init__(
- self,
- indent_increment: int = 2,
- width: t.Optional[int] = None,
- max_width: t.Optional[int] = None,
- ) -> None:
- import shutil
-
- self.indent_increment = indent_increment
- if max_width is None:
- max_width = 80
- if width is None:
- width = FORCED_WIDTH
- if width is None:
- width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50)
- self.width = width
- self.current_indent = 0
- self.buffer: t.List[str] = []
-
- def write(self, string: str) -> None:
- """Writes a unicode string into the internal buffer."""
- self.buffer.append(string)
-
- def indent(self) -> None:
- """Increases the indentation."""
- self.current_indent += self.indent_increment
-
- def dedent(self) -> None:
- """Decreases the indentation."""
- self.current_indent -= self.indent_increment
-
- def write_usage(
- self, prog: str, args: str = "", prefix: t.Optional[str] = None
- ) -> None:
- """Writes a usage line into the buffer.
-
- :param prog: the program name.
- :param args: whitespace separated list of arguments.
- :param prefix: The prefix for the first line. Defaults to
- ``"Usage: "``.
- """
- if prefix is None:
- prefix = f"{_('Usage:')} "
-
- usage_prefix = f"{prefix:>{self.current_indent}}{prog} "
- text_width = self.width - self.current_indent
-
- if text_width >= (term_len(usage_prefix) + 20):
- # The arguments will fit to the right of the prefix.
- indent = " " * term_len(usage_prefix)
- self.write(
- wrap_text(
- args,
- text_width,
- initial_indent=usage_prefix,
- subsequent_indent=indent,
- )
- )
- else:
- # The prefix is too long, put the arguments on the next line.
- self.write(usage_prefix)
- self.write("\n")
- indent = " " * (max(self.current_indent, term_len(prefix)) + 4)
- self.write(
- wrap_text(
- args, text_width, initial_indent=indent, subsequent_indent=indent
- )
- )
-
- self.write("\n")
-
- def write_heading(self, heading: str) -> None:
- """Writes a heading into the buffer."""
- self.write(f"{'':>{self.current_indent}}{heading}:\n")
-
- def write_paragraph(self) -> None:
- """Writes a paragraph into the buffer."""
- if self.buffer:
- self.write("\n")
-
- def write_text(self, text: str) -> None:
- """Writes re-indented text into the buffer. This rewraps and
- preserves paragraphs.
- """
- indent = " " * self.current_indent
- self.write(
- wrap_text(
- text,
- self.width,
- initial_indent=indent,
- subsequent_indent=indent,
- preserve_paragraphs=True,
- )
- )
- self.write("\n")
-
- def write_dl(
- self,
- rows: t.Sequence[t.Tuple[str, str]],
- col_max: int = 30,
- col_spacing: int = 2,
- ) -> None:
- """Writes a definition list into the buffer. This is how options
- and commands are usually formatted.
-
- :param rows: a list of two item tuples for the terms and values.
- :param col_max: the maximum width of the first column.
- :param col_spacing: the number of spaces between the first and
- second column.
- """
- rows = list(rows)
- widths = measure_table(rows)
- if len(widths) != 2:
- raise TypeError("Expected two columns for definition list")
-
- first_col = min(widths[0], col_max) + col_spacing
-
- for first, second in iter_rows(rows, len(widths)):
- self.write(f"{'':>{self.current_indent}}{first}")
- if not second:
- self.write("\n")
- continue
- if term_len(first) <= first_col - col_spacing:
- self.write(" " * (first_col - term_len(first)))
- else:
- self.write("\n")
- self.write(" " * (first_col + self.current_indent))
-
- text_width = max(self.width - first_col - 2, 10)
- wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True)
- lines = wrapped_text.splitlines()
-
- if lines:
- self.write(f"{lines[0]}\n")
-
- for line in lines[1:]:
- self.write(f"{'':>{first_col + self.current_indent}}{line}\n")
- else:
- self.write("\n")
-
- @contextmanager
- def section(self, name: str) -> t.Iterator[None]:
- """Helpful context manager that writes a paragraph, a heading,
- and the indents.
-
- :param name: the section name that is written as heading.
- """
- self.write_paragraph()
- self.write_heading(name)
- self.indent()
- try:
- yield
- finally:
- self.dedent()
-
- @contextmanager
- def indentation(self) -> t.Iterator[None]:
- """A context manager that increases the indentation."""
- self.indent()
- try:
- yield
- finally:
- self.dedent()
-
- def getvalue(self) -> str:
- """Returns the buffer contents."""
- return "".join(self.buffer)
-
-
-def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]:
- """Given a list of option strings this joins them in the most appropriate
- way and returns them in the form ``(formatted_string,
- any_prefix_is_slash)`` where the second item in the tuple is a flag that
- indicates if any of the option prefixes was a slash.
- """
- rv = []
- any_prefix_is_slash = False
-
- for opt in options:
- prefix = split_opt(opt)[0]
-
- if prefix == "/":
- any_prefix_is_slash = True
-
- rv.append((len(prefix), opt))
-
- rv.sort(key=lambda x: x[0])
- return ", ".join(x[1] for x in rv), any_prefix_is_slash
diff --git a/venv/lib/python3.9/site-packages/click/globals.py b/venv/lib/python3.9/site-packages/click/globals.py
deleted file mode 100644
index cfcade1..0000000
--- a/venv/lib/python3.9/site-packages/click/globals.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import typing
-import typing as t
-from threading import local
-
-if t.TYPE_CHECKING:
- import typing_extensions as te
- from .core import Context
-
-_local = local()
-
-
-@typing.overload
-def get_current_context(silent: "te.Literal[False]" = False) -> "Context":
- ...
-
-
-@typing.overload
-def get_current_context(silent: bool = ...) -> t.Optional["Context"]:
- ...
-
-
-def get_current_context(silent: bool = False) -> t.Optional["Context"]:
- """Returns the current click context. This can be used as a way to
- access the current context object from anywhere. This is a more implicit
- alternative to the :func:`pass_context` decorator. This function is
- primarily useful for helpers such as :func:`echo` which might be
- interested in changing its behavior based on the current context.
-
- To push the current context, :meth:`Context.scope` can be used.
-
- .. versionadded:: 5.0
-
- :param silent: if set to `True` the return value is `None` if no context
- is available. The default behavior is to raise a
- :exc:`RuntimeError`.
- """
- try:
- return t.cast("Context", _local.stack[-1])
- except (AttributeError, IndexError):
- if not silent:
- raise RuntimeError("There is no active click context.")
-
- return None
-
-
-def push_context(ctx: "Context") -> None:
- """Pushes a new context to the current stack."""
- _local.__dict__.setdefault("stack", []).append(ctx)
-
-
-def pop_context() -> None:
- """Removes the top level from the stack."""
- _local.stack.pop()
-
-
-def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]:
- """Internal helper to get the default value of the color flag. If a
- value is passed it's returned unchanged, otherwise it's looked up from
- the current context.
- """
- if color is not None:
- return color
-
- ctx = get_current_context(silent=True)
-
- if ctx is not None:
- return ctx.color
-
- return None
diff --git a/venv/lib/python3.9/site-packages/click/parser.py b/venv/lib/python3.9/site-packages/click/parser.py
deleted file mode 100644
index 7d995f7..0000000
--- a/venv/lib/python3.9/site-packages/click/parser.py
+++ /dev/null
@@ -1,529 +0,0 @@
-"""
-This module started out as largely a copy paste from the stdlib's
-optparse module with the features removed that we do not need from
-optparse because we implement them in Click on a higher level (for
-instance type handling, help formatting and a lot more).
-
-The plan is to remove more and more from here over time.
-
-The reason this is a different module and not optparse from the stdlib
-is that there are differences in 2.x and 3.x about the error messages
-generated and optparse in the stdlib uses gettext for no good reason
-and might cause us issues.
-
-Click uses parts of optparse written by Gregory P. Ward and maintained
-by the Python Software Foundation. This is limited to code in parser.py.
-
-Copyright 2001-2006 Gregory P. Ward. All rights reserved.
-Copyright 2002-2006 Python Software Foundation. All rights reserved.
-"""
-# This code uses parts of optparse written by Gregory P. Ward and
-# maintained by the Python Software Foundation.
-# Copyright 2001-2006 Gregory P. Ward
-# Copyright 2002-2006 Python Software Foundation
-import typing as t
-from collections import deque
-from gettext import gettext as _
-from gettext import ngettext
-
-from .exceptions import BadArgumentUsage
-from .exceptions import BadOptionUsage
-from .exceptions import NoSuchOption
-from .exceptions import UsageError
-
-if t.TYPE_CHECKING:
- import typing_extensions as te
- from .core import Argument as CoreArgument
- from .core import Context
- from .core import Option as CoreOption
- from .core import Parameter as CoreParameter
-
-V = t.TypeVar("V")
-
-# Sentinel value that indicates an option was passed as a flag without a
-# value but is not a flag option. Option.consume_value uses this to
-# prompt or use the flag_value.
-_flag_needs_value = object()
-
-
-def _unpack_args(
- args: t.Sequence[str], nargs_spec: t.Sequence[int]
-) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]:
- """Given an iterable of arguments and an iterable of nargs specifications,
- it returns a tuple with all the unpacked arguments at the first index
- and all remaining arguments as the second.
-
- The nargs specification is the number of arguments that should be consumed
- or `-1` to indicate that this position should eat up all the remainders.
-
- Missing items are filled with `None`.
- """
- args = deque(args)
- nargs_spec = deque(nargs_spec)
- rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = []
- spos: t.Optional[int] = None
-
- def _fetch(c: "te.Deque[V]") -> t.Optional[V]:
- try:
- if spos is None:
- return c.popleft()
- else:
- return c.pop()
- except IndexError:
- return None
-
- while nargs_spec:
- nargs = _fetch(nargs_spec)
-
- if nargs is None:
- continue
-
- if nargs == 1:
- rv.append(_fetch(args))
- elif nargs > 1:
- x = [_fetch(args) for _ in range(nargs)]
-
- # If we're reversed, we're pulling in the arguments in reverse,
- # so we need to turn them around.
- if spos is not None:
- x.reverse()
-
- rv.append(tuple(x))
- elif nargs < 0:
- if spos is not None:
- raise TypeError("Cannot have two nargs < 0")
-
- spos = len(rv)
- rv.append(None)
-
- # spos is the position of the wildcard (star). If it's not `None`,
- # we fill it with the remainder.
- if spos is not None:
- rv[spos] = tuple(args)
- args = []
- rv[spos + 1 :] = reversed(rv[spos + 1 :])
-
- return tuple(rv), list(args)
-
-
-def split_opt(opt: str) -> t.Tuple[str, str]:
- first = opt[:1]
- if first.isalnum():
- return "", opt
- if opt[1:2] == first:
- return opt[:2], opt[2:]
- return first, opt[1:]
-
-
-def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str:
- if ctx is None or ctx.token_normalize_func is None:
- return opt
- prefix, opt = split_opt(opt)
- return f"{prefix}{ctx.token_normalize_func(opt)}"
-
-
-def split_arg_string(string: str) -> t.List[str]:
- """Split an argument string as with :func:`shlex.split`, but don't
- fail if the string is incomplete. Ignores a missing closing quote or
- incomplete escape sequence and uses the partial token as-is.
-
- .. code-block:: python
-
- split_arg_string("example 'my file")
- ["example", "my file"]
-
- split_arg_string("example my\\")
- ["example", "my"]
-
- :param string: String to split.
- """
- import shlex
-
- lex = shlex.shlex(string, posix=True)
- lex.whitespace_split = True
- lex.commenters = ""
- out = []
-
- try:
- for token in lex:
- out.append(token)
- except ValueError:
- # Raised when end-of-string is reached in an invalid state. Use
- # the partial token as-is. The quote or escape character is in
- # lex.state, not lex.token.
- out.append(lex.token)
-
- return out
-
-
-class Option:
- def __init__(
- self,
- obj: "CoreOption",
- opts: t.Sequence[str],
- dest: t.Optional[str],
- action: t.Optional[str] = None,
- nargs: int = 1,
- const: t.Optional[t.Any] = None,
- ):
- self._short_opts = []
- self._long_opts = []
- self.prefixes = set()
-
- for opt in opts:
- prefix, value = split_opt(opt)
- if not prefix:
- raise ValueError(f"Invalid start character for option ({opt})")
- self.prefixes.add(prefix[0])
- if len(prefix) == 1 and len(value) == 1:
- self._short_opts.append(opt)
- else:
- self._long_opts.append(opt)
- self.prefixes.add(prefix)
-
- if action is None:
- action = "store"
-
- self.dest = dest
- self.action = action
- self.nargs = nargs
- self.const = const
- self.obj = obj
-
- @property
- def takes_value(self) -> bool:
- return self.action in ("store", "append")
-
- def process(self, value: str, state: "ParsingState") -> None:
- if self.action == "store":
- state.opts[self.dest] = value # type: ignore
- elif self.action == "store_const":
- state.opts[self.dest] = self.const # type: ignore
- elif self.action == "append":
- state.opts.setdefault(self.dest, []).append(value) # type: ignore
- elif self.action == "append_const":
- state.opts.setdefault(self.dest, []).append(self.const) # type: ignore
- elif self.action == "count":
- state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore
- else:
- raise ValueError(f"unknown action '{self.action}'")
- state.order.append(self.obj)
-
-
-class Argument:
- def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1):
- self.dest = dest
- self.nargs = nargs
- self.obj = obj
-
- def process(
- self,
- value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]],
- state: "ParsingState",
- ) -> None:
- if self.nargs > 1:
- assert value is not None
- holes = sum(1 for x in value if x is None)
- if holes == len(value):
- value = None
- elif holes != 0:
- raise BadArgumentUsage(
- _("Argument {name!r} takes {nargs} values.").format(
- name=self.dest, nargs=self.nargs
- )
- )
-
- if self.nargs == -1 and self.obj.envvar is not None and value == ():
- # Replace empty tuple with None so that a value from the
- # environment may be tried.
- value = None
-
- state.opts[self.dest] = value # type: ignore
- state.order.append(self.obj)
-
-
-class ParsingState:
- def __init__(self, rargs: t.List[str]) -> None:
- self.opts: t.Dict[str, t.Any] = {}
- self.largs: t.List[str] = []
- self.rargs = rargs
- self.order: t.List["CoreParameter"] = []
-
-
-class OptionParser:
- """The option parser is an internal class that is ultimately used to
- parse options and arguments. It's modelled after optparse and brings
- a similar but vastly simplified API. It should generally not be used
- directly as the high level Click classes wrap it for you.
-
- It's not nearly as extensible as optparse or argparse as it does not
- implement features that are implemented on a higher level (such as
- types or defaults).
-
- :param ctx: optionally the :class:`~click.Context` where this parser
- should go with.
- """
-
- def __init__(self, ctx: t.Optional["Context"] = None) -> None:
- #: The :class:`~click.Context` for this parser. This might be
- #: `None` for some advanced use cases.
- self.ctx = ctx
- #: This controls how the parser deals with interspersed arguments.
- #: If this is set to `False`, the parser will stop on the first
- #: non-option. Click uses this to implement nested subcommands
- #: safely.
- self.allow_interspersed_args = True
- #: This tells the parser how to deal with unknown options. By
- #: default it will error out (which is sensible), but there is a
- #: second mode where it will ignore it and continue processing
- #: after shifting all the unknown options into the resulting args.
- self.ignore_unknown_options = False
-
- if ctx is not None:
- self.allow_interspersed_args = ctx.allow_interspersed_args
- self.ignore_unknown_options = ctx.ignore_unknown_options
-
- self._short_opt: t.Dict[str, Option] = {}
- self._long_opt: t.Dict[str, Option] = {}
- self._opt_prefixes = {"-", "--"}
- self._args: t.List[Argument] = []
-
- def add_option(
- self,
- obj: "CoreOption",
- opts: t.Sequence[str],
- dest: t.Optional[str],
- action: t.Optional[str] = None,
- nargs: int = 1,
- const: t.Optional[t.Any] = None,
- ) -> None:
- """Adds a new option named `dest` to the parser. The destination
- is not inferred (unlike with optparse) and needs to be explicitly
- provided. Action can be any of ``store``, ``store_const``,
- ``append``, ``appnd_const`` or ``count``.
-
- The `obj` can be used to identify the option in the order list
- that is returned from the parser.
- """
- opts = [normalize_opt(opt, self.ctx) for opt in opts]
- option = Option(obj, opts, dest, action=action, nargs=nargs, const=const)
- self._opt_prefixes.update(option.prefixes)
- for opt in option._short_opts:
- self._short_opt[opt] = option
- for opt in option._long_opts:
- self._long_opt[opt] = option
-
- def add_argument(
- self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1
- ) -> None:
- """Adds a positional argument named `dest` to the parser.
-
- The `obj` can be used to identify the option in the order list
- that is returned from the parser.
- """
- self._args.append(Argument(obj, dest=dest, nargs=nargs))
-
- def parse_args(
- self, args: t.List[str]
- ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]:
- """Parses positional arguments and returns ``(values, args, order)``
- for the parsed options and arguments as well as the leftover
- arguments if there are any. The order is a list of objects as they
- appear on the command line. If arguments appear multiple times they
- will be memorized multiple times as well.
- """
- state = ParsingState(args)
- try:
- self._process_args_for_options(state)
- self._process_args_for_args(state)
- except UsageError:
- if self.ctx is None or not self.ctx.resilient_parsing:
- raise
- return state.opts, state.largs, state.order
-
- def _process_args_for_args(self, state: ParsingState) -> None:
- pargs, args = _unpack_args(
- state.largs + state.rargs, [x.nargs for x in self._args]
- )
-
- for idx, arg in enumerate(self._args):
- arg.process(pargs[idx], state)
-
- state.largs = args
- state.rargs = []
-
- def _process_args_for_options(self, state: ParsingState) -> None:
- while state.rargs:
- arg = state.rargs.pop(0)
- arglen = len(arg)
- # Double dashes always handled explicitly regardless of what
- # prefixes are valid.
- if arg == "--":
- return
- elif arg[:1] in self._opt_prefixes and arglen > 1:
- self._process_opts(arg, state)
- elif self.allow_interspersed_args:
- state.largs.append(arg)
- else:
- state.rargs.insert(0, arg)
- return
-
- # Say this is the original argument list:
- # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
- # ^
- # (we are about to process arg(i)).
- #
- # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
- # [arg0, ..., arg(i-1)] (any options and their arguments will have
- # been removed from largs).
- #
- # The while loop will usually consume 1 or more arguments per pass.
- # If it consumes 1 (eg. arg is an option that takes no arguments),
- # then after _process_arg() is done the situation is:
- #
- # largs = subset of [arg0, ..., arg(i)]
- # rargs = [arg(i+1), ..., arg(N-1)]
- #
- # If allow_interspersed_args is false, largs will always be
- # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
- # not a very interesting subset!
-
- def _match_long_opt(
- self, opt: str, explicit_value: t.Optional[str], state: ParsingState
- ) -> None:
- if opt not in self._long_opt:
- from difflib import get_close_matches
-
- possibilities = get_close_matches(opt, self._long_opt)
- raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx)
-
- option = self._long_opt[opt]
- if option.takes_value:
- # At this point it's safe to modify rargs by injecting the
- # explicit value, because no exception is raised in this
- # branch. This means that the inserted value will be fully
- # consumed.
- if explicit_value is not None:
- state.rargs.insert(0, explicit_value)
-
- value = self._get_value_from_state(opt, option, state)
-
- elif explicit_value is not None:
- raise BadOptionUsage(
- opt, _("Option {name!r} does not take a value.").format(name=opt)
- )
-
- else:
- value = None
-
- option.process(value, state)
-
- def _match_short_opt(self, arg: str, state: ParsingState) -> None:
- stop = False
- i = 1
- prefix = arg[0]
- unknown_options = []
-
- for ch in arg[1:]:
- opt = normalize_opt(f"{prefix}{ch}", self.ctx)
- option = self._short_opt.get(opt)
- i += 1
-
- if not option:
- if self.ignore_unknown_options:
- unknown_options.append(ch)
- continue
- raise NoSuchOption(opt, ctx=self.ctx)
- if option.takes_value:
- # Any characters left in arg? Pretend they're the
- # next arg, and stop consuming characters of arg.
- if i < len(arg):
- state.rargs.insert(0, arg[i:])
- stop = True
-
- value = self._get_value_from_state(opt, option, state)
-
- else:
- value = None
-
- option.process(value, state)
-
- if stop:
- break
-
- # If we got any unknown options we re-combinate the string of the
- # remaining options and re-attach the prefix, then report that
- # to the state as new larg. This way there is basic combinatorics
- # that can be achieved while still ignoring unknown arguments.
- if self.ignore_unknown_options and unknown_options:
- state.largs.append(f"{prefix}{''.join(unknown_options)}")
-
- def _get_value_from_state(
- self, option_name: str, option: Option, state: ParsingState
- ) -> t.Any:
- nargs = option.nargs
-
- if len(state.rargs) < nargs:
- if option.obj._flag_needs_value:
- # Option allows omitting the value.
- value = _flag_needs_value
- else:
- raise BadOptionUsage(
- option_name,
- ngettext(
- "Option {name!r} requires an argument.",
- "Option {name!r} requires {nargs} arguments.",
- nargs,
- ).format(name=option_name, nargs=nargs),
- )
- elif nargs == 1:
- next_rarg = state.rargs[0]
-
- if (
- option.obj._flag_needs_value
- and isinstance(next_rarg, str)
- and next_rarg[:1] in self._opt_prefixes
- and len(next_rarg) > 1
- ):
- # The next arg looks like the start of an option, don't
- # use it as the value if omitting the value is allowed.
- value = _flag_needs_value
- else:
- value = state.rargs.pop(0)
- else:
- value = tuple(state.rargs[:nargs])
- del state.rargs[:nargs]
-
- return value
-
- def _process_opts(self, arg: str, state: ParsingState) -> None:
- explicit_value = None
- # Long option handling happens in two parts. The first part is
- # supporting explicitly attached values. In any case, we will try
- # to long match the option first.
- if "=" in arg:
- long_opt, explicit_value = arg.split("=", 1)
- else:
- long_opt = arg
- norm_long_opt = normalize_opt(long_opt, self.ctx)
-
- # At this point we will match the (assumed) long option through
- # the long option matching code. Note that this allows options
- # like "-foo" to be matched as long options.
- try:
- self._match_long_opt(norm_long_opt, explicit_value, state)
- except NoSuchOption:
- # At this point the long option matching failed, and we need
- # to try with short options. However there is a special rule
- # which says, that if we have a two character options prefix
- # (applies to "--foo" for instance), we do not dispatch to the
- # short option code and will instead raise the no option
- # error.
- if arg[:2] not in self._opt_prefixes:
- self._match_short_opt(arg, state)
- return
-
- if not self.ignore_unknown_options:
- raise
-
- state.largs.append(arg)
diff --git a/venv/lib/python3.9/site-packages/click/py.typed b/venv/lib/python3.9/site-packages/click/py.typed
deleted file mode 100644
index e69de29..0000000
diff --git a/venv/lib/python3.9/site-packages/click/shell_completion.py b/venv/lib/python3.9/site-packages/click/shell_completion.py
deleted file mode 100644
index 706fb69..0000000
--- a/venv/lib/python3.9/site-packages/click/shell_completion.py
+++ /dev/null
@@ -1,574 +0,0 @@
-import os
-import re
-import typing as t
-from gettext import gettext as _
-
-from .core import Argument
-from .core import BaseCommand
-from .core import Context
-from .core import MultiCommand
-from .core import Option
-from .core import Parameter
-from .core import ParameterSource
-from .parser import split_arg_string
-from .utils import echo
-
-
-def shell_complete(
- cli: BaseCommand,
- ctx_args: t.Dict[str, t.Any],
- prog_name: str,
- complete_var: str,
- instruction: str,
-) -> int:
- """Perform shell completion for the given CLI program.
-
- :param cli: Command being called.
- :param ctx_args: Extra arguments to pass to
- ``cli.make_context``.
- :param prog_name: Name of the executable in the shell.
- :param complete_var: Name of the environment variable that holds
- the completion instruction.
- :param instruction: Value of ``complete_var`` with the completion
- instruction and shell, in the form ``instruction_shell``.
- :return: Status code to exit with.
- """
- shell, _, instruction = instruction.partition("_")
- comp_cls = get_completion_class(shell)
-
- if comp_cls is None:
- return 1
-
- comp = comp_cls(cli, ctx_args, prog_name, complete_var)
-
- if instruction == "source":
- echo(comp.source())
- return 0
-
- if instruction == "complete":
- echo(comp.complete())
- return 0
-
- return 1
-
-
-class CompletionItem:
- """Represents a completion value and metadata about the value. The
- default metadata is ``type`` to indicate special shell handling,
- and ``help`` if a shell supports showing a help string next to the
- value.
-
- Arbitrary parameters can be passed when creating the object, and
- accessed using ``item.attr``. If an attribute wasn't passed,
- accessing it returns ``None``.
-
- :param value: The completion suggestion.
- :param type: Tells the shell script to provide special completion
- support for the type. Click uses ``"dir"`` and ``"file"``.
- :param help: String shown next to the value if supported.
- :param kwargs: Arbitrary metadata. The built-in implementations
- don't use this, but custom type completions paired with custom
- shell support could use it.
- """
-
- __slots__ = ("value", "type", "help", "_info")
-
- def __init__(
- self,
- value: t.Any,
- type: str = "plain",
- help: t.Optional[str] = None,
- **kwargs: t.Any,
- ) -> None:
- self.value = value
- self.type = type
- self.help = help
- self._info = kwargs
-
- def __getattr__(self, name: str) -> t.Any:
- return self._info.get(name)
-
-
-# Only Bash >= 4.4 has the nosort option.
-_SOURCE_BASH = """\
-%(complete_func)s() {
- local IFS=$'\\n'
- local response
-
- response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \
-%(complete_var)s=bash_complete $1)
-
- for completion in $response; do
- IFS=',' read type value <<< "$completion"
-
- if [[ $type == 'dir' ]]; then
- COMREPLY=()
- compopt -o dirnames
- elif [[ $type == 'file' ]]; then
- COMREPLY=()
- compopt -o default
- elif [[ $type == 'plain' ]]; then
- COMPREPLY+=($value)
- fi
- done
-
- return 0
-}
-
-%(complete_func)s_setup() {
- complete -o nosort -F %(complete_func)s %(prog_name)s
-}
-
-%(complete_func)s_setup;
-"""
-
-_SOURCE_ZSH = """\
-#compdef %(prog_name)s
-
-%(complete_func)s() {
- local -a completions
- local -a completions_with_descriptions
- local -a response
- (( ! $+commands[%(prog_name)s] )) && return 1
-
- response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \
-%(complete_var)s=zsh_complete %(prog_name)s)}")
-
- for type key descr in ${response}; do
- if [[ "$type" == "plain" ]]; then
- if [[ "$descr" == "_" ]]; then
- completions+=("$key")
- else
- completions_with_descriptions+=("$key":"$descr")
- fi
- elif [[ "$type" == "dir" ]]; then
- _path_files -/
- elif [[ "$type" == "file" ]]; then
- _path_files -f
- fi
- done
-
- if [ -n "$completions_with_descriptions" ]; then
- _describe -V unsorted completions_with_descriptions -U
- fi
-
- if [ -n "$completions" ]; then
- compadd -U -V unsorted -a completions
- fi
-}
-
-compdef %(complete_func)s %(prog_name)s;
-"""
-
-_SOURCE_FISH = """\
-function %(complete_func)s;
- set -l response;
-
- for value in (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \
-COMP_CWORD=(commandline -t) %(prog_name)s);
- set response $response $value;
- end;
-
- for completion in $response;
- set -l metadata (string split "," $completion);
-
- if test $metadata[1] = "dir";
- __fish_complete_directories $metadata[2];
- else if test $metadata[1] = "file";
- __fish_complete_path $metadata[2];
- else if test $metadata[1] = "plain";
- echo $metadata[2];
- end;
- end;
-end;
-
-complete --no-files --command %(prog_name)s --arguments \
-"(%(complete_func)s)";
-"""
-
-
-class ShellComplete:
- """Base class for providing shell completion support. A subclass for
- a given shell will override attributes and methods to implement the
- completion instructions (``source`` and ``complete``).
-
- :param cli: Command being called.
- :param prog_name: Name of the executable in the shell.
- :param complete_var: Name of the environment variable that holds
- the completion instruction.
-
- .. versionadded:: 8.0
- """
-
- name: t.ClassVar[str]
- """Name to register the shell as with :func:`add_completion_class`.
- This is used in completion instructions (``{name}_source`` and
- ``{name}_complete``).
- """
-
- source_template: t.ClassVar[str]
- """Completion script template formatted by :meth:`source`. This must
- be provided by subclasses.
- """
-
- def __init__(
- self,
- cli: BaseCommand,
- ctx_args: t.Dict[str, t.Any],
- prog_name: str,
- complete_var: str,
- ) -> None:
- self.cli = cli
- self.ctx_args = ctx_args
- self.prog_name = prog_name
- self.complete_var = complete_var
-
- @property
- def func_name(self) -> str:
- """The name of the shell function defined by the completion
- script.
- """
- safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), re.ASCII)
- return f"_{safe_name}_completion"
-
- def source_vars(self) -> t.Dict[str, t.Any]:
- """Vars for formatting :attr:`source_template`.
-
- By default this provides ``complete_func``, ``complete_var``,
- and ``prog_name``.
- """
- return {
- "complete_func": self.func_name,
- "complete_var": self.complete_var,
- "prog_name": self.prog_name,
- }
-
- def source(self) -> str:
- """Produce the shell script that defines the completion
- function. By default this ``%``-style formats
- :attr:`source_template` with the dict returned by
- :meth:`source_vars`.
- """
- return self.source_template % self.source_vars()
-
- def get_completion_args(self) -> t.Tuple[t.List[str], str]:
- """Use the env vars defined by the shell script to return a
- tuple of ``args, incomplete``. This must be implemented by
- subclasses.
- """
- raise NotImplementedError
-
- def get_completions(
- self, args: t.List[str], incomplete: str
- ) -> t.List[CompletionItem]:
- """Determine the context and last complete command or parameter
- from the complete args. Call that object's ``shell_complete``
- method to get the completions for the incomplete value.
-
- :param args: List of complete args before the incomplete value.
- :param incomplete: Value being completed. May be empty.
- """
- ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args)
- obj, incomplete = _resolve_incomplete(ctx, args, incomplete)
- return obj.shell_complete(ctx, incomplete)
-
- def format_completion(self, item: CompletionItem) -> str:
- """Format a completion item into the form recognized by the
- shell script. This must be implemented by subclasses.
-
- :param item: Completion item to format.
- """
- raise NotImplementedError
-
- def complete(self) -> str:
- """Produce the completion data to send back to the shell.
-
- By default this calls :meth:`get_completion_args`, gets the
- completions, then calls :meth:`format_completion` for each
- completion.
- """
- args, incomplete = self.get_completion_args()
- completions = self.get_completions(args, incomplete)
- out = [self.format_completion(item) for item in completions]
- return "\n".join(out)
-
-
-class BashComplete(ShellComplete):
- """Shell completion for Bash."""
-
- name = "bash"
- source_template = _SOURCE_BASH
-
- def _check_version(self) -> None:
- import subprocess
-
- output = subprocess.run(["bash", "--version"], stdout=subprocess.PIPE)
- match = re.search(r"version (\d)\.(\d)\.\d", output.stdout.decode())
-
- if match is not None:
- major, minor = match.groups()
-
- if major < "4" or major == "4" and minor < "4":
- raise RuntimeError(
- _(
- "Shell completion is not supported for Bash"
- " versions older than 4.4."
- )
- )
- else:
- raise RuntimeError(
- _("Couldn't detect Bash version, shell completion is not supported.")
- )
-
- def source(self) -> str:
- self._check_version()
- return super().source()
-
- def get_completion_args(self) -> t.Tuple[t.List[str], str]:
- cwords = split_arg_string(os.environ["COMP_WORDS"])
- cword = int(os.environ["COMP_CWORD"])
- args = cwords[1:cword]
-
- try:
- incomplete = cwords[cword]
- except IndexError:
- incomplete = ""
-
- return args, incomplete
-
- def format_completion(self, item: CompletionItem) -> str:
- return f"{item.type},{item.value}"
-
-
-class ZshComplete(ShellComplete):
- """Shell completion for Zsh."""
-
- name = "zsh"
- source_template = _SOURCE_ZSH
-
- def get_completion_args(self) -> t.Tuple[t.List[str], str]:
- cwords = split_arg_string(os.environ["COMP_WORDS"])
- cword = int(os.environ["COMP_CWORD"])
- args = cwords[1:cword]
-
- try:
- incomplete = cwords[cword]
- except IndexError:
- incomplete = ""
-
- return args, incomplete
-
- def format_completion(self, item: CompletionItem) -> str:
- return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}"
-
-
-class FishComplete(ShellComplete):
- """Shell completion for Fish."""
-
- name = "fish"
- source_template = _SOURCE_FISH
-
- def get_completion_args(self) -> t.Tuple[t.List[str], str]:
- cwords = split_arg_string(os.environ["COMP_WORDS"])
- incomplete = os.environ["COMP_CWORD"]
- args = cwords[1:]
-
- # Fish stores the partial word in both COMP_WORDS and
- # COMP_CWORD, remove it from complete args.
- if incomplete and args and args[-1] == incomplete:
- args.pop()
-
- return args, incomplete
-
- def format_completion(self, item: CompletionItem) -> str:
- if item.help:
- return f"{item.type},{item.value}\t{item.help}"
-
- return f"{item.type},{item.value}"
-
-
-_available_shells: t.Dict[str, t.Type[ShellComplete]] = {
- "bash": BashComplete,
- "fish": FishComplete,
- "zsh": ZshComplete,
-}
-
-
-def add_completion_class(
- cls: t.Type[ShellComplete], name: t.Optional[str] = None
-) -> None:
- """Register a :class:`ShellComplete` subclass under the given name.
- The name will be provided by the completion instruction environment
- variable during completion.
-
- :param cls: The completion class that will handle completion for the
- shell.
- :param name: Name to register the class under. Defaults to the
- class's ``name`` attribute.
- """
- if name is None:
- name = cls.name
-
- _available_shells[name] = cls
-
-
-def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]:
- """Look up a registered :class:`ShellComplete` subclass by the name
- provided by the completion instruction environment variable. If the
- name isn't registered, returns ``None``.
-
- :param shell: Name the class is registered under.
- """
- return _available_shells.get(shell)
-
-
-def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool:
- """Determine if the given parameter is an argument that can still
- accept values.
-
- :param ctx: Invocation context for the command represented by the
- parsed complete args.
- :param param: Argument object being checked.
- """
- if not isinstance(param, Argument):
- return False
-
- assert param.name is not None
- value = ctx.params[param.name]
- return (
- param.nargs == -1
- or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE
- or (
- param.nargs > 1
- and isinstance(value, (tuple, list))
- and len(value) < param.nargs
- )
- )
-
-
-def _start_of_option(value: str) -> bool:
- """Check if the value looks like the start of an option."""
- return not value[0].isalnum() if value else False
-
-
-def _is_incomplete_option(args: t.List[str], param: Parameter) -> bool:
- """Determine if the given parameter is an option that needs a value.
-
- :param args: List of complete args before the incomplete value.
- :param param: Option object being checked.
- """
- if not isinstance(param, Option):
- return False
-
- if param.is_flag:
- return False
-
- last_option = None
-
- for index, arg in enumerate(reversed(args)):
- if index + 1 > param.nargs:
- break
-
- if _start_of_option(arg):
- last_option = arg
-
- return last_option is not None and last_option in param.opts
-
-
-def _resolve_context(
- cli: BaseCommand, ctx_args: t.Dict[str, t.Any], prog_name: str, args: t.List[str]
-) -> Context:
- """Produce the context hierarchy starting with the command and
- traversing the complete arguments. This only follows the commands,
- it doesn't trigger input prompts or callbacks.
-
- :param cli: Command being called.
- :param prog_name: Name of the executable in the shell.
- :param args: List of complete args before the incomplete value.
- """
- ctx_args["resilient_parsing"] = True
- ctx = cli.make_context(prog_name, args.copy(), **ctx_args)
- args = ctx.protected_args + ctx.args
-
- while args:
- command = ctx.command
-
- if isinstance(command, MultiCommand):
- if not command.chain:
- name, cmd, args = command.resolve_command(ctx, args)
-
- if cmd is None:
- return ctx
-
- ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True)
- args = ctx.protected_args + ctx.args
- else:
- while args:
- name, cmd, args = command.resolve_command(ctx, args)
-
- if cmd is None:
- return ctx
-
- sub_ctx = cmd.make_context(
- name,
- args,
- parent=ctx,
- allow_extra_args=True,
- allow_interspersed_args=False,
- resilient_parsing=True,
- )
- args = sub_ctx.args
-
- ctx = sub_ctx
- args = [*sub_ctx.protected_args, *sub_ctx.args]
- else:
- break
-
- return ctx
-
-
-def _resolve_incomplete(
- ctx: Context, args: t.List[str], incomplete: str
-) -> t.Tuple[t.Union[BaseCommand, Parameter], str]:
- """Find the Click object that will handle the completion of the
- incomplete value. Return the object and the incomplete value.
-
- :param ctx: Invocation context for the command represented by
- the parsed complete args.
- :param args: List of complete args before the incomplete value.
- :param incomplete: Value being completed. May be empty.
- """
- # Different shells treat an "=" between a long option name and
- # value differently. Might keep the value joined, return the "="
- # as a separate item, or return the split name and value. Always
- # split and discard the "=" to make completion easier.
- if incomplete == "=":
- incomplete = ""
- elif "=" in incomplete and _start_of_option(incomplete):
- name, _, incomplete = incomplete.partition("=")
- args.append(name)
-
- # The "--" marker tells Click to stop treating values as options
- # even if they start with the option character. If it hasn't been
- # given and the incomplete arg looks like an option, the current
- # command will provide option name completions.
- if "--" not in args and _start_of_option(incomplete):
- return ctx.command, incomplete
-
- params = ctx.command.get_params(ctx)
-
- # If the last complete arg is an option name with an incomplete
- # value, the option will provide value completions.
- for param in params:
- if _is_incomplete_option(args, param):
- return param, incomplete
-
- # It's not an option name or value. The first argument without a
- # parsed value will provide value completions.
- for param in params:
- if _is_incomplete_argument(ctx, param):
- return param, incomplete
-
- # There were no unparsed arguments, the command may be a group that
- # will provide command name completions.
- return ctx.command, incomplete
diff --git a/venv/lib/python3.9/site-packages/click/termui.py b/venv/lib/python3.9/site-packages/click/termui.py
deleted file mode 100644
index 034fe6e..0000000
--- a/venv/lib/python3.9/site-packages/click/termui.py
+++ /dev/null
@@ -1,807 +0,0 @@
-import inspect
-import io
-import itertools
-import os
-import sys
-import typing
-import typing as t
-from gettext import gettext as _
-
-from ._compat import isatty
-from ._compat import strip_ansi
-from ._compat import WIN
-from .exceptions import Abort
-from .exceptions import UsageError
-from .globals import resolve_color_default
-from .types import Choice
-from .types import convert_type
-from .types import ParamType
-from .utils import echo
-from .utils import LazyFile
-
-if t.TYPE_CHECKING:
- from ._termui_impl import ProgressBar
-
-V = t.TypeVar("V")
-
-# The prompt functions to use. The doc tools currently override these
-# functions to customize how they work.
-visible_prompt_func: t.Callable[[str], str] = input
-
-_ansi_colors = {
- "black": 30,
- "red": 31,
- "green": 32,
- "yellow": 33,
- "blue": 34,
- "magenta": 35,
- "cyan": 36,
- "white": 37,
- "reset": 39,
- "bright_black": 90,
- "bright_red": 91,
- "bright_green": 92,
- "bright_yellow": 93,
- "bright_blue": 94,
- "bright_magenta": 95,
- "bright_cyan": 96,
- "bright_white": 97,
-}
-_ansi_reset_all = "\033[0m"
-
-
-def hidden_prompt_func(prompt: str) -> str:
- import getpass
-
- return getpass.getpass(prompt)
-
-
-def _build_prompt(
- text: str,
- suffix: str,
- show_default: bool = False,
- default: t.Optional[t.Any] = None,
- show_choices: bool = True,
- type: t.Optional[ParamType] = None,
-) -> str:
- prompt = text
- if type is not None and show_choices and isinstance(type, Choice):
- prompt += f" ({', '.join(map(str, type.choices))})"
- if default is not None and show_default:
- prompt = f"{prompt} [{_format_default(default)}]"
- return f"{prompt}{suffix}"
-
-
-def _format_default(default: t.Any) -> t.Any:
- if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"):
- return default.name # type: ignore
-
- return default
-
-
-def prompt(
- text: str,
- default: t.Optional[t.Any] = None,
- hide_input: bool = False,
- confirmation_prompt: t.Union[bool, str] = False,
- type: t.Optional[ParamType] = None,
- value_proc: t.Optional[t.Callable[[str], t.Any]] = None,
- prompt_suffix: str = ": ",
- show_default: bool = True,
- err: bool = False,
- show_choices: bool = True,
-) -> t.Any:
- """Prompts a user for input. This is a convenience function that can
- be used to prompt a user for input later.
-
- If the user aborts the input by sending a interrupt signal, this
- function will catch it and raise a :exc:`Abort` exception.
-
- :param text: the text to show for the prompt.
- :param default: the default value to use if no input happens. If this
- is not given it will prompt until it's aborted.
- :param hide_input: if this is set to true then the input value will
- be hidden.
- :param confirmation_prompt: Prompt a second time to confirm the
- value. Can be set to a string instead of ``True`` to customize
- the message.
- :param type: the type to use to check the value against.
- :param value_proc: if this parameter is provided it's a function that
- is invoked instead of the type conversion to
- convert a value.
- :param prompt_suffix: a suffix that should be added to the prompt.
- :param show_default: shows or hides the default value in the prompt.
- :param err: if set to true the file defaults to ``stderr`` instead of
- ``stdout``, the same as with echo.
- :param show_choices: Show or hide choices if the passed type is a Choice.
- For example if type is a Choice of either day or week,
- show_choices is true and text is "Group by" then the
- prompt will be "Group by (day, week): ".
-
- .. versionadded:: 8.0
- ``confirmation_prompt`` can be a custom string.
-
- .. versionadded:: 7.0
- Added the ``show_choices`` parameter.
-
- .. versionadded:: 6.0
- Added unicode support for cmd.exe on Windows.
-
- .. versionadded:: 4.0
- Added the `err` parameter.
-
- """
-
- def prompt_func(text: str) -> str:
- f = hidden_prompt_func if hide_input else visible_prompt_func
- try:
- # Write the prompt separately so that we get nice
- # coloring through colorama on Windows
- echo(text.rstrip(" "), nl=False, err=err)
- # Echo a space to stdout to work around an issue where
- # readline causes backspace to clear the whole line.
- return f(" ")
- except (KeyboardInterrupt, EOFError):
- # getpass doesn't print a newline if the user aborts input with ^C.
- # Allegedly this behavior is inherited from getpass(3).
- # A doc bug has been filed at https://bugs.python.org/issue24711
- if hide_input:
- echo(None, err=err)
- raise Abort()
-
- if value_proc is None:
- value_proc = convert_type(type, default)
-
- prompt = _build_prompt(
- text, prompt_suffix, show_default, default, show_choices, type
- )
-
- if confirmation_prompt:
- if confirmation_prompt is True:
- confirmation_prompt = _("Repeat for confirmation")
-
- confirmation_prompt = t.cast(str, confirmation_prompt)
- confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix)
-
- while True:
- while True:
- value = prompt_func(prompt)
- if value:
- break
- elif default is not None:
- value = default
- break
- try:
- result = value_proc(value)
- except UsageError as e:
- if hide_input:
- echo(_("Error: The value you entered was invalid."), err=err)
- else:
- echo(_("Error: {e.message}").format(e=e), err=err) # noqa: B306
- continue
- if not confirmation_prompt:
- return result
- while True:
- confirmation_prompt = t.cast(str, confirmation_prompt)
- value2 = prompt_func(confirmation_prompt)
- if value2:
- break
- if value == value2:
- return result
- echo(_("Error: The two entered values do not match."), err=err)
-
-
-def confirm(
- text: str,
- default: t.Optional[bool] = False,
- abort: bool = False,
- prompt_suffix: str = ": ",
- show_default: bool = True,
- err: bool = False,
-) -> bool:
- """Prompts for confirmation (yes/no question).
-
- If the user aborts the input by sending a interrupt signal this
- function will catch it and raise a :exc:`Abort` exception.
-
- :param text: the question to ask.
- :param default: The default value to use when no input is given. If
- ``None``, repeat until input is given.
- :param abort: if this is set to `True` a negative answer aborts the
- exception by raising :exc:`Abort`.
- :param prompt_suffix: a suffix that should be added to the prompt.
- :param show_default: shows or hides the default value in the prompt.
- :param err: if set to true the file defaults to ``stderr`` instead of
- ``stdout``, the same as with echo.
-
- .. versionchanged:: 8.0
- Repeat until input is given if ``default`` is ``None``.
-
- .. versionadded:: 4.0
- Added the ``err`` parameter.
- """
- prompt = _build_prompt(
- text,
- prompt_suffix,
- show_default,
- "y/n" if default is None else ("Y/n" if default else "y/N"),
- )
-
- while True:
- try:
- # Write the prompt separately so that we get nice
- # coloring through colorama on Windows
- echo(prompt, nl=False, err=err)
- value = visible_prompt_func("").lower().strip()
- except (KeyboardInterrupt, EOFError):
- raise Abort()
- if value in ("y", "yes"):
- rv = True
- elif value in ("n", "no"):
- rv = False
- elif default is not None and value == "":
- rv = default
- else:
- echo(_("Error: invalid input"), err=err)
- continue
- break
- if abort and not rv:
- raise Abort()
- return rv
-
-
-def get_terminal_size() -> os.terminal_size:
- """Returns the current size of the terminal as tuple in the form
- ``(width, height)`` in columns and rows.
-
- .. deprecated:: 8.0
- Will be removed in Click 8.1. Use
- :func:`shutil.get_terminal_size` instead.
- """
- import shutil
- import warnings
-
- warnings.warn(
- "'click.get_terminal_size()' is deprecated and will be removed"
- " in Click 8.1. Use 'shutil.get_terminal_size()' instead.",
- DeprecationWarning,
- stacklevel=2,
- )
- return shutil.get_terminal_size()
-
-
-def echo_via_pager(
- text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str],
- color: t.Optional[bool] = None,
-) -> None:
- """This function takes a text and shows it via an environment specific
- pager on stdout.
-
- .. versionchanged:: 3.0
- Added the `color` flag.
-
- :param text_or_generator: the text to page, or alternatively, a
- generator emitting the text to page.
- :param color: controls if the pager supports ANSI colors or not. The
- default is autodetection.
- """
- color = resolve_color_default(color)
-
- if inspect.isgeneratorfunction(text_or_generator):
- i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)()
- elif isinstance(text_or_generator, str):
- i = [text_or_generator]
- else:
- i = iter(t.cast(t.Iterable[str], text_or_generator))
-
- # convert every element of i to a text type if necessary
- text_generator = (el if isinstance(el, str) else str(el) for el in i)
-
- from ._termui_impl import pager
-
- return pager(itertools.chain(text_generator, "\n"), color)
-
-
-def progressbar(
- iterable: t.Optional[t.Iterable[V]] = None,
- length: t.Optional[int] = None,
- label: t.Optional[str] = None,
- show_eta: bool = True,
- show_percent: t.Optional[bool] = None,
- show_pos: bool = False,
- item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None,
- fill_char: str = "#",
- empty_char: str = "-",
- bar_template: str = "%(label)s [%(bar)s] %(info)s",
- info_sep: str = " ",
- width: int = 36,
- file: t.Optional[t.TextIO] = None,
- color: t.Optional[bool] = None,
- update_min_steps: int = 1,
-) -> "ProgressBar[V]":
- """This function creates an iterable context manager that can be used
- to iterate over something while showing a progress bar. It will
- either iterate over the `iterable` or `length` items (that are counted
- up). While iteration happens, this function will print a rendered
- progress bar to the given `file` (defaults to stdout) and will attempt
- to calculate remaining time and more. By default, this progress bar
- will not be rendered if the file is not a terminal.
-
- The context manager creates the progress bar. When the context
- manager is entered the progress bar is already created. With every
- iteration over the progress bar, the iterable passed to the bar is
- advanced and the bar is updated. When the context manager exits,
- a newline is printed and the progress bar is finalized on screen.
-
- Note: The progress bar is currently designed for use cases where the
- total progress can be expected to take at least several seconds.
- Because of this, the ProgressBar class object won't display
- progress that is considered too fast, and progress where the time
- between steps is less than a second.
-
- No printing must happen or the progress bar will be unintentionally
- destroyed.
-
- Example usage::
-
- with progressbar(items) as bar:
- for item in bar:
- do_something_with(item)
-
- Alternatively, if no iterable is specified, one can manually update the
- progress bar through the `update()` method instead of directly
- iterating over the progress bar. The update method accepts the number
- of steps to increment the bar with::
-
- with progressbar(length=chunks.total_bytes) as bar:
- for chunk in chunks:
- process_chunk(chunk)
- bar.update(chunks.bytes)
-
- The ``update()`` method also takes an optional value specifying the
- ``current_item`` at the new position. This is useful when used
- together with ``item_show_func`` to customize the output for each
- manual step::
-
- with click.progressbar(
- length=total_size,
- label='Unzipping archive',
- item_show_func=lambda a: a.filename
- ) as bar:
- for archive in zip_file:
- archive.extract()
- bar.update(archive.size, archive)
-
- :param iterable: an iterable to iterate over. If not provided the length
- is required.
- :param length: the number of items to iterate over. By default the
- progressbar will attempt to ask the iterator about its
- length, which might or might not work. If an iterable is
- also provided this parameter can be used to override the
- length. If an iterable is not provided the progress bar
- will iterate over a range of that length.
- :param label: the label to show next to the progress bar.
- :param show_eta: enables or disables the estimated time display. This is
- automatically disabled if the length cannot be
- determined.
- :param show_percent: enables or disables the percentage display. The
- default is `True` if the iterable has a length or
- `False` if not.
- :param show_pos: enables or disables the absolute position display. The
- default is `False`.
- :param item_show_func: A function called with the current item which
- can return a string to show next to the progress bar. If the
- function returns ``None`` nothing is shown. The current item can
- be ``None``, such as when entering and exiting the bar.
- :param fill_char: the character to use to show the filled part of the
- progress bar.
- :param empty_char: the character to use to show the non-filled part of
- the progress bar.
- :param bar_template: the format string to use as template for the bar.
- The parameters in it are ``label`` for the label,
- ``bar`` for the progress bar and ``info`` for the
- info section.
- :param info_sep: the separator between multiple info items (eta etc.)
- :param width: the width of the progress bar in characters, 0 means full
- terminal width
- :param file: The file to write to. If this is not a terminal then
- only the label is printed.
- :param color: controls if the terminal supports ANSI colors or not. The
- default is autodetection. This is only needed if ANSI
- codes are included anywhere in the progress bar output
- which is not the case by default.
- :param update_min_steps: Render only when this many updates have
- completed. This allows tuning for very fast iterators.
-
- .. versionchanged:: 8.0
- Output is shown even if execution time is less than 0.5 seconds.
-
- .. versionchanged:: 8.0
- ``item_show_func`` shows the current item, not the previous one.
-
- .. versionchanged:: 8.0
- Labels are echoed if the output is not a TTY. Reverts a change
- in 7.0 that removed all output.
-
- .. versionadded:: 8.0
- Added the ``update_min_steps`` parameter.
-
- .. versionchanged:: 4.0
- Added the ``color`` parameter. Added the ``update`` method to
- the object.
-
- .. versionadded:: 2.0
- """
- from ._termui_impl import ProgressBar
-
- color = resolve_color_default(color)
- return ProgressBar(
- iterable=iterable,
- length=length,
- show_eta=show_eta,
- show_percent=show_percent,
- show_pos=show_pos,
- item_show_func=item_show_func,
- fill_char=fill_char,
- empty_char=empty_char,
- bar_template=bar_template,
- info_sep=info_sep,
- file=file,
- label=label,
- width=width,
- color=color,
- update_min_steps=update_min_steps,
- )
-
-
-def clear() -> None:
- """Clears the terminal screen. This will have the effect of clearing
- the whole visible space of the terminal and moving the cursor to the
- top left. This does not do anything if not connected to a terminal.
-
- .. versionadded:: 2.0
- """
- if not isatty(sys.stdout):
- return
- if WIN:
- os.system("cls")
- else:
- sys.stdout.write("\033[2J\033[1;1H")
-
-
-def _interpret_color(
- color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0
-) -> str:
- if isinstance(color, int):
- return f"{38 + offset};5;{color:d}"
-
- if isinstance(color, (tuple, list)):
- r, g, b = color
- return f"{38 + offset};2;{r:d};{g:d};{b:d}"
-
- return str(_ansi_colors[color] + offset)
-
-
-def style(
- text: t.Any,
- fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None,
- bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None,
- bold: t.Optional[bool] = None,
- dim: t.Optional[bool] = None,
- underline: t.Optional[bool] = None,
- overline: t.Optional[bool] = None,
- italic: t.Optional[bool] = None,
- blink: t.Optional[bool] = None,
- reverse: t.Optional[bool] = None,
- strikethrough: t.Optional[bool] = None,
- reset: bool = True,
-) -> str:
- """Styles a text with ANSI styles and returns the new string. By
- default the styling is self contained which means that at the end
- of the string a reset code is issued. This can be prevented by
- passing ``reset=False``.
-
- Examples::
-
- click.echo(click.style('Hello World!', fg='green'))
- click.echo(click.style('ATTENTION!', blink=True))
- click.echo(click.style('Some things', reverse=True, fg='cyan'))
- click.echo(click.style('More colors', fg=(255, 12, 128), bg=117))
-
- Supported color names:
-
- * ``black`` (might be a gray)
- * ``red``
- * ``green``
- * ``yellow`` (might be an orange)
- * ``blue``
- * ``magenta``
- * ``cyan``
- * ``white`` (might be light gray)
- * ``bright_black``
- * ``bright_red``
- * ``bright_green``
- * ``bright_yellow``
- * ``bright_blue``
- * ``bright_magenta``
- * ``bright_cyan``
- * ``bright_white``
- * ``reset`` (reset the color code only)
-
- If the terminal supports it, color may also be specified as:
-
- - An integer in the interval [0, 255]. The terminal must support
- 8-bit/256-color mode.
- - An RGB tuple of three integers in [0, 255]. The terminal must
- support 24-bit/true-color mode.
-
- See https://en.wikipedia.org/wiki/ANSI_color and
- https://gist.github.com/XVilka/8346728 for more information.
-
- :param text: the string to style with ansi codes.
- :param fg: if provided this will become the foreground color.
- :param bg: if provided this will become the background color.
- :param bold: if provided this will enable or disable bold mode.
- :param dim: if provided this will enable or disable dim mode. This is
- badly supported.
- :param underline: if provided this will enable or disable underline.
- :param overline: if provided this will enable or disable overline.
- :param italic: if provided this will enable or disable italic.
- :param blink: if provided this will enable or disable blinking.
- :param reverse: if provided this will enable or disable inverse
- rendering (foreground becomes background and the
- other way round).
- :param strikethrough: if provided this will enable or disable
- striking through text.
- :param reset: by default a reset-all code is added at the end of the
- string which means that styles do not carry over. This
- can be disabled to compose styles.
-
- .. versionchanged:: 8.0
- A non-string ``message`` is converted to a string.
-
- .. versionchanged:: 8.0
- Added support for 256 and RGB color codes.
-
- .. versionchanged:: 8.0
- Added the ``strikethrough``, ``italic``, and ``overline``
- parameters.
-
- .. versionchanged:: 7.0
- Added support for bright colors.
-
- .. versionadded:: 2.0
- """
- if not isinstance(text, str):
- text = str(text)
-
- bits = []
-
- if fg:
- try:
- bits.append(f"\033[{_interpret_color(fg)}m")
- except KeyError:
- raise TypeError(f"Unknown color {fg!r}")
-
- if bg:
- try:
- bits.append(f"\033[{_interpret_color(bg, 10)}m")
- except KeyError:
- raise TypeError(f"Unknown color {bg!r}")
-
- if bold is not None:
- bits.append(f"\033[{1 if bold else 22}m")
- if dim is not None:
- bits.append(f"\033[{2 if dim else 22}m")
- if underline is not None:
- bits.append(f"\033[{4 if underline else 24}m")
- if overline is not None:
- bits.append(f"\033[{53 if underline else 55}m")
- if italic is not None:
- bits.append(f"\033[{5 if underline else 23}m")
- if blink is not None:
- bits.append(f"\033[{5 if blink else 25}m")
- if reverse is not None:
- bits.append(f"\033[{7 if reverse else 27}m")
- if strikethrough is not None:
- bits.append(f"\033[{9 if strikethrough else 29}m")
- bits.append(text)
- if reset:
- bits.append(_ansi_reset_all)
- return "".join(bits)
-
-
-def unstyle(text: str) -> str:
- """Removes ANSI styling information from a string. Usually it's not
- necessary to use this function as Click's echo function will
- automatically remove styling if necessary.
-
- .. versionadded:: 2.0
-
- :param text: the text to remove style information from.
- """
- return strip_ansi(text)
-
-
-def secho(
- message: t.Optional[t.Any] = None,
- file: t.Optional[t.IO] = None,
- nl: bool = True,
- err: bool = False,
- color: t.Optional[bool] = None,
- **styles: t.Any,
-) -> None:
- """This function combines :func:`echo` and :func:`style` into one
- call. As such the following two calls are the same::
-
- click.secho('Hello World!', fg='green')
- click.echo(click.style('Hello World!', fg='green'))
-
- All keyword arguments are forwarded to the underlying functions
- depending on which one they go with.
-
- Non-string types will be converted to :class:`str`. However,
- :class:`bytes` are passed directly to :meth:`echo` without applying
- style. If you want to style bytes that represent text, call
- :meth:`bytes.decode` first.
-
- .. versionchanged:: 8.0
- A non-string ``message`` is converted to a string. Bytes are
- passed through without style applied.
-
- .. versionadded:: 2.0
- """
- if message is not None and not isinstance(message, (bytes, bytearray)):
- message = style(message, **styles)
-
- return echo(message, file=file, nl=nl, err=err, color=color)
-
-
-def edit(
- text: t.Optional[t.AnyStr] = None,
- editor: t.Optional[str] = None,
- env: t.Optional[t.Mapping[str, str]] = None,
- require_save: bool = True,
- extension: str = ".txt",
- filename: t.Optional[str] = None,
-) -> t.Optional[t.AnyStr]:
- r"""Edits the given text in the defined editor. If an editor is given
- (should be the full path to the executable but the regular operating
- system search path is used for finding the executable) it overrides
- the detected editor. Optionally, some environment variables can be
- used. If the editor is closed without changes, `None` is returned. In
- case a file is edited directly the return value is always `None` and
- `require_save` and `extension` are ignored.
-
- If the editor cannot be opened a :exc:`UsageError` is raised.
-
- Note for Windows: to simplify cross-platform usage, the newlines are
- automatically converted from POSIX to Windows and vice versa. As such,
- the message here will have ``\n`` as newline markers.
-
- :param text: the text to edit.
- :param editor: optionally the editor to use. Defaults to automatic
- detection.
- :param env: environment variables to forward to the editor.
- :param require_save: if this is true, then not saving in the editor
- will make the return value become `None`.
- :param extension: the extension to tell the editor about. This defaults
- to `.txt` but changing this might change syntax
- highlighting.
- :param filename: if provided it will edit this file instead of the
- provided text contents. It will not use a temporary
- file as an indirection in that case.
- """
- from ._termui_impl import Editor
-
- ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension)
-
- if filename is None:
- return ed.edit(text)
-
- ed.edit_file(filename)
- return None
-
-
-def launch(url: str, wait: bool = False, locate: bool = False) -> int:
- """This function launches the given URL (or filename) in the default
- viewer application for this file type. If this is an executable, it
- might launch the executable in a new session. The return value is
- the exit code of the launched application. Usually, ``0`` indicates
- success.
-
- Examples::
-
- click.launch('https://click.palletsprojects.com/')
- click.launch('/my/downloaded/file', locate=True)
-
- .. versionadded:: 2.0
-
- :param url: URL or filename of the thing to launch.
- :param wait: Wait for the program to exit before returning. This
- only works if the launched program blocks. In particular,
- ``xdg-open`` on Linux does not block.
- :param locate: if this is set to `True` then instead of launching the
- application associated with the URL it will attempt to
- launch a file manager with the file located. This
- might have weird effects if the URL does not point to
- the filesystem.
- """
- from ._termui_impl import open_url
-
- return open_url(url, wait=wait, locate=locate)
-
-
-# If this is provided, getchar() calls into this instead. This is used
-# for unittesting purposes.
-_getchar: t.Optional[t.Callable[[bool], str]] = None
-
-
-def getchar(echo: bool = False) -> str:
- """Fetches a single character from the terminal and returns it. This
- will always return a unicode character and under certain rare
- circumstances this might return more than one character. The
- situations which more than one character is returned is when for
- whatever reason multiple characters end up in the terminal buffer or
- standard input was not actually a terminal.
-
- Note that this will always read from the terminal, even if something
- is piped into the standard input.
-
- Note for Windows: in rare cases when typing non-ASCII characters, this
- function might wait for a second character and then return both at once.
- This is because certain Unicode characters look like special-key markers.
-
- .. versionadded:: 2.0
-
- :param echo: if set to `True`, the character read will also show up on
- the terminal. The default is to not show it.
- """
- global _getchar
-
- if _getchar is None:
- from ._termui_impl import getchar as f
-
- _getchar = f
-
- return _getchar(echo)
-
-
-def raw_terminal() -> t.ContextManager[int]:
- from ._termui_impl import raw_terminal as f
-
- return f()
-
-
-def pause(info: t.Optional[str] = None, err: bool = False) -> None:
- """This command stops execution and waits for the user to press any
- key to continue. This is similar to the Windows batch "pause"
- command. If the program is not run through a terminal, this command
- will instead do nothing.
-
- .. versionadded:: 2.0
-
- .. versionadded:: 4.0
- Added the `err` parameter.
-
- :param info: The message to print before pausing. Defaults to
- ``"Press any key to continue..."``.
- :param err: if set to message goes to ``stderr`` instead of
- ``stdout``, the same as with echo.
- """
- if not isatty(sys.stdin) or not isatty(sys.stdout):
- return
-
- if info is None:
- info = _("Press any key to continue...")
-
- try:
- if info:
- echo(info, nl=False, err=err)
- try:
- getchar()
- except (KeyboardInterrupt, EOFError):
- pass
- finally:
- if info:
- echo(err=err)
diff --git a/venv/lib/python3.9/site-packages/click/testing.py b/venv/lib/python3.9/site-packages/click/testing.py
deleted file mode 100644
index d19b850..0000000
--- a/venv/lib/python3.9/site-packages/click/testing.py
+++ /dev/null
@@ -1,479 +0,0 @@
-import contextlib
-import io
-import os
-import shlex
-import shutil
-import sys
-import tempfile
-import typing as t
-from types import TracebackType
-
-from . import formatting
-from . import termui
-from . import utils
-from ._compat import _find_binary_reader
-
-if t.TYPE_CHECKING:
- from .core import BaseCommand
-
-
-class EchoingStdin:
- def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None:
- self._input = input
- self._output = output
- self._paused = False
-
- def __getattr__(self, x: str) -> t.Any:
- return getattr(self._input, x)
-
- def _echo(self, rv: bytes) -> bytes:
- if not self._paused:
- self._output.write(rv)
-
- return rv
-
- def read(self, n: int = -1) -> bytes:
- return self._echo(self._input.read(n))
-
- def read1(self, n: int = -1) -> bytes:
- return self._echo(self._input.read1(n)) # type: ignore
-
- def readline(self, n: int = -1) -> bytes:
- return self._echo(self._input.readline(n))
-
- def readlines(self) -> t.List[bytes]:
- return [self._echo(x) for x in self._input.readlines()]
-
- def __iter__(self) -> t.Iterator[bytes]:
- return iter(self._echo(x) for x in self._input)
-
- def __repr__(self) -> str:
- return repr(self._input)
-
-
-@contextlib.contextmanager
-def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]:
- if stream is None:
- yield
- else:
- stream._paused = True
- yield
- stream._paused = False
-
-
-class _NamedTextIOWrapper(io.TextIOWrapper):
- def __init__(
- self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any
- ) -> None:
- super().__init__(buffer, **kwargs)
- self._name = name
- self._mode = mode
-
- @property
- def name(self) -> str:
- return self._name
-
- @property
- def mode(self) -> str:
- return self._mode
-
-
-def make_input_stream(
- input: t.Optional[t.Union[str, bytes, t.IO]], charset: str
-) -> t.BinaryIO:
- # Is already an input stream.
- if hasattr(input, "read"):
- rv = _find_binary_reader(t.cast(t.IO, input))
-
- if rv is not None:
- return rv
-
- raise TypeError("Could not find binary reader for input stream.")
-
- if input is None:
- input = b""
- elif isinstance(input, str):
- input = input.encode(charset)
-
- return io.BytesIO(t.cast(bytes, input))
-
-
-class Result:
- """Holds the captured result of an invoked CLI script."""
-
- def __init__(
- self,
- runner: "CliRunner",
- stdout_bytes: bytes,
- stderr_bytes: t.Optional[bytes],
- return_value: t.Any,
- exit_code: int,
- exception: t.Optional[BaseException],
- exc_info: t.Optional[
- t.Tuple[t.Type[BaseException], BaseException, TracebackType]
- ] = None,
- ):
- #: The runner that created the result
- self.runner = runner
- #: The standard output as bytes.
- self.stdout_bytes = stdout_bytes
- #: The standard error as bytes, or None if not available
- self.stderr_bytes = stderr_bytes
- #: The value returned from the invoked command.
- #:
- #: .. versionadded:: 8.0
- self.return_value = return_value
- #: The exit code as integer.
- self.exit_code = exit_code
- #: The exception that happened if one did.
- self.exception = exception
- #: The traceback
- self.exc_info = exc_info
-
- @property
- def output(self) -> str:
- """The (standard) output as unicode string."""
- return self.stdout
-
- @property
- def stdout(self) -> str:
- """The standard output as unicode string."""
- return self.stdout_bytes.decode(self.runner.charset, "replace").replace(
- "\r\n", "\n"
- )
-
- @property
- def stderr(self) -> str:
- """The standard error as unicode string."""
- if self.stderr_bytes is None:
- raise ValueError("stderr not separately captured")
- return self.stderr_bytes.decode(self.runner.charset, "replace").replace(
- "\r\n", "\n"
- )
-
- def __repr__(self) -> str:
- exc_str = repr(self.exception) if self.exception else "okay"
- return f"<{type(self).__name__} {exc_str}>"
-
-
-class CliRunner:
- """The CLI runner provides functionality to invoke a Click command line
- script for unittesting purposes in a isolated environment. This only
- works in single-threaded systems without any concurrency as it changes the
- global interpreter state.
-
- :param charset: the character set for the input and output data.
- :param env: a dictionary with environment variables for overriding.
- :param echo_stdin: if this is set to `True`, then reading from stdin writes
- to stdout. This is useful for showing examples in
- some circumstances. Note that regular prompts
- will automatically echo the input.
- :param mix_stderr: if this is set to `False`, then stdout and stderr are
- preserved as independent streams. This is useful for
- Unix-philosophy apps that have predictable stdout and
- noisy stderr, such that each may be measured
- independently
- """
-
- def __init__(
- self,
- charset: str = "utf-8",
- env: t.Optional[t.Mapping[str, t.Optional[str]]] = None,
- echo_stdin: bool = False,
- mix_stderr: bool = True,
- ) -> None:
- self.charset = charset
- self.env = env or {}
- self.echo_stdin = echo_stdin
- self.mix_stderr = mix_stderr
-
- def get_default_prog_name(self, cli: "BaseCommand") -> str:
- """Given a command object it will return the default program name
- for it. The default is the `name` attribute or ``"root"`` if not
- set.
- """
- return cli.name or "root"
-
- def make_env(
- self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None
- ) -> t.Mapping[str, t.Optional[str]]:
- """Returns the environment overrides for invoking a script."""
- rv = dict(self.env)
- if overrides:
- rv.update(overrides)
- return rv
-
- @contextlib.contextmanager
- def isolation(
- self,
- input: t.Optional[t.Union[str, bytes, t.IO]] = None,
- env: t.Optional[t.Mapping[str, t.Optional[str]]] = None,
- color: bool = False,
- ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]:
- """A context manager that sets up the isolation for invoking of a
- command line tool. This sets up stdin with the given input data
- and `os.environ` with the overrides from the given dictionary.
- This also rebinds some internals in Click to be mocked (like the
- prompt functionality).
-
- This is automatically done in the :meth:`invoke` method.
-
- :param input: the input stream to put into sys.stdin.
- :param env: the environment overrides as dictionary.
- :param color: whether the output should contain color codes. The
- application can still override this explicitly.
-
- .. versionchanged:: 8.0
- ``stderr`` is opened with ``errors="backslashreplace"``
- instead of the default ``"strict"``.
-
- .. versionchanged:: 4.0
- Added the ``color`` parameter.
- """
- bytes_input = make_input_stream(input, self.charset)
- echo_input = None
-
- old_stdin = sys.stdin
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- old_forced_width = formatting.FORCED_WIDTH
- formatting.FORCED_WIDTH = 80
-
- env = self.make_env(env)
-
- bytes_output = io.BytesIO()
-
- if self.echo_stdin:
- bytes_input = echo_input = t.cast(
- t.BinaryIO, EchoingStdin(bytes_input, bytes_output)
- )
-
- sys.stdin = text_input = _NamedTextIOWrapper(
- bytes_input, encoding=self.charset, name="", mode="r"
- )
-
- if self.echo_stdin:
- # Force unbuffered reads, otherwise TextIOWrapper reads a
- # large chunk which is echoed early.
- text_input._CHUNK_SIZE = 1 # type: ignore
-
- sys.stdout = _NamedTextIOWrapper(
- bytes_output, encoding=self.charset, name="", mode="w"
- )
-
- bytes_error = None
- if self.mix_stderr:
- sys.stderr = sys.stdout
- else:
- bytes_error = io.BytesIO()
- sys.stderr = _NamedTextIOWrapper(
- bytes_error,
- encoding=self.charset,
- name="",
- mode="w",
- errors="backslashreplace",
- )
-
- @_pause_echo(echo_input) # type: ignore
- def visible_input(prompt: t.Optional[str] = None) -> str:
- sys.stdout.write(prompt or "")
- val = text_input.readline().rstrip("\r\n")
- sys.stdout.write(f"{val}\n")
- sys.stdout.flush()
- return val
-
- @_pause_echo(echo_input) # type: ignore
- def hidden_input(prompt: t.Optional[str] = None) -> str:
- sys.stdout.write(f"{prompt or ''}\n")
- sys.stdout.flush()
- return text_input.readline().rstrip("\r\n")
-
- @_pause_echo(echo_input) # type: ignore
- def _getchar(echo: bool) -> str:
- char = sys.stdin.read(1)
-
- if echo:
- sys.stdout.write(char)
-
- sys.stdout.flush()
- return char
-
- default_color = color
-
- def should_strip_ansi(
- stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None
- ) -> bool:
- if color is None:
- return not default_color
- return not color
-
- old_visible_prompt_func = termui.visible_prompt_func
- old_hidden_prompt_func = termui.hidden_prompt_func
- old__getchar_func = termui._getchar
- old_should_strip_ansi = utils.should_strip_ansi # type: ignore
- termui.visible_prompt_func = visible_input
- termui.hidden_prompt_func = hidden_input
- termui._getchar = _getchar
- utils.should_strip_ansi = should_strip_ansi # type: ignore
-
- old_env = {}
- try:
- for key, value in env.items():
- old_env[key] = os.environ.get(key)
- if value is None:
- try:
- del os.environ[key]
- except Exception:
- pass
- else:
- os.environ[key] = value
- yield (bytes_output, bytes_error)
- finally:
- for key, value in old_env.items():
- if value is None:
- try:
- del os.environ[key]
- except Exception:
- pass
- else:
- os.environ[key] = value
- sys.stdout = old_stdout
- sys.stderr = old_stderr
- sys.stdin = old_stdin
- termui.visible_prompt_func = old_visible_prompt_func
- termui.hidden_prompt_func = old_hidden_prompt_func
- termui._getchar = old__getchar_func
- utils.should_strip_ansi = old_should_strip_ansi # type: ignore
- formatting.FORCED_WIDTH = old_forced_width
-
- def invoke(
- self,
- cli: "BaseCommand",
- args: t.Optional[t.Union[str, t.Sequence[str]]] = None,
- input: t.Optional[t.Union[str, bytes, t.IO]] = None,
- env: t.Optional[t.Mapping[str, t.Optional[str]]] = None,
- catch_exceptions: bool = True,
- color: bool = False,
- **extra: t.Any,
- ) -> Result:
- """Invokes a command in an isolated environment. The arguments are
- forwarded directly to the command line script, the `extra` keyword
- arguments are passed to the :meth:`~clickpkg.Command.main` function of
- the command.
-
- This returns a :class:`Result` object.
-
- :param cli: the command to invoke
- :param args: the arguments to invoke. It may be given as an iterable
- or a string. When given as string it will be interpreted
- as a Unix shell command. More details at
- :func:`shlex.split`.
- :param input: the input data for `sys.stdin`.
- :param env: the environment overrides.
- :param catch_exceptions: Whether to catch any other exceptions than
- ``SystemExit``.
- :param extra: the keyword arguments to pass to :meth:`main`.
- :param color: whether the output should contain color codes. The
- application can still override this explicitly.
-
- .. versionchanged:: 8.0
- The result object has the ``return_value`` attribute with
- the value returned from the invoked command.
-
- .. versionchanged:: 4.0
- Added the ``color`` parameter.
-
- .. versionchanged:: 3.0
- Added the ``catch_exceptions`` parameter.
-
- .. versionchanged:: 3.0
- The result object has the ``exc_info`` attribute with the
- traceback if available.
- """
- exc_info = None
- with self.isolation(input=input, env=env, color=color) as outstreams:
- return_value = None
- exception: t.Optional[BaseException] = None
- exit_code = 0
-
- if isinstance(args, str):
- args = shlex.split(args)
-
- try:
- prog_name = extra.pop("prog_name")
- except KeyError:
- prog_name = self.get_default_prog_name(cli)
-
- try:
- return_value = cli.main(args=args or (), prog_name=prog_name, **extra)
- except SystemExit as e:
- exc_info = sys.exc_info()
- e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code)
-
- if e_code is None:
- e_code = 0
-
- if e_code != 0:
- exception = e
-
- if not isinstance(e_code, int):
- sys.stdout.write(str(e_code))
- sys.stdout.write("\n")
- e_code = 1
-
- exit_code = e_code
-
- except Exception as e:
- if not catch_exceptions:
- raise
- exception = e
- exit_code = 1
- exc_info = sys.exc_info()
- finally:
- sys.stdout.flush()
- stdout = outstreams[0].getvalue()
- if self.mix_stderr:
- stderr = None
- else:
- stderr = outstreams[1].getvalue() # type: ignore
-
- return Result(
- runner=self,
- stdout_bytes=stdout,
- stderr_bytes=stderr,
- return_value=return_value,
- exit_code=exit_code,
- exception=exception,
- exc_info=exc_info, # type: ignore
- )
-
- @contextlib.contextmanager
- def isolated_filesystem(
- self, temp_dir: t.Optional[t.Union[str, os.PathLike]] = None
- ) -> t.Iterator[str]:
- """A context manager that creates a temporary directory and
- changes the current working directory to it. This isolates tests
- that affect the contents of the CWD to prevent them from
- interfering with each other.
-
- :param temp_dir: Create the temporary directory under this
- directory. If given, the created directory is not removed
- when exiting.
-
- .. versionchanged:: 8.0
- Added the ``temp_dir`` parameter.
- """
- cwd = os.getcwd()
- t = tempfile.mkdtemp(dir=temp_dir)
- os.chdir(t)
-
- try:
- yield t
- finally:
- os.chdir(cwd)
-
- if temp_dir is None:
- try:
- shutil.rmtree(t)
- except OSError: # noqa: B014
- pass
diff --git a/venv/lib/python3.9/site-packages/click/types.py b/venv/lib/python3.9/site-packages/click/types.py
deleted file mode 100644
index 21f0e4f..0000000
--- a/venv/lib/python3.9/site-packages/click/types.py
+++ /dev/null
@@ -1,1052 +0,0 @@
-import os
-import stat
-import typing as t
-from datetime import datetime
-from gettext import gettext as _
-from gettext import ngettext
-
-from ._compat import _get_argv_encoding
-from ._compat import get_filesystem_encoding
-from ._compat import open_stream
-from .exceptions import BadParameter
-from .utils import LazyFile
-from .utils import safecall
-
-if t.TYPE_CHECKING:
- import typing_extensions as te
- from .core import Context
- from .core import Parameter
- from .shell_completion import CompletionItem
-
-
-class ParamType:
- """Represents the type of a parameter. Validates and converts values
- from the command line or Python into the correct type.
-
- To implement a custom type, subclass and implement at least the
- following:
-
- - The :attr:`name` class attribute must be set.
- - Calling an instance of the type with ``None`` must return
- ``None``. This is already implemented by default.
- - :meth:`convert` must convert string values to the correct type.
- - :meth:`convert` must accept values that are already the correct
- type.
- - It must be able to convert a value if the ``ctx`` and ``param``
- arguments are ``None``. This can occur when converting prompt
- input.
- """
-
- is_composite: t.ClassVar[bool] = False
- arity: t.ClassVar[int] = 1
-
- #: the descriptive name of this type
- name: str
-
- #: if a list of this type is expected and the value is pulled from a
- #: string environment variable, this is what splits it up. `None`
- #: means any whitespace. For all parameters the general rule is that
- #: whitespace splits them up. The exception are paths and files which
- #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on
- #: Windows).
- envvar_list_splitter: t.ClassVar[t.Optional[str]] = None
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- """Gather information that could be useful for a tool generating
- user-facing documentation.
-
- Use :meth:`click.Context.to_info_dict` to traverse the entire
- CLI structure.
-
- .. versionadded:: 8.0
- """
- # The class name without the "ParamType" suffix.
- param_type = type(self).__name__.partition("ParamType")[0]
- param_type = param_type.partition("ParameterType")[0]
- return {"param_type": param_type, "name": self.name}
-
- def __call__(
- self,
- value: t.Any,
- param: t.Optional["Parameter"] = None,
- ctx: t.Optional["Context"] = None,
- ) -> t.Any:
- if value is not None:
- return self.convert(value, param, ctx)
-
- def get_metavar(self, param: "Parameter") -> t.Optional[str]:
- """Returns the metavar default for this param if it provides one."""
-
- def get_missing_message(self, param: "Parameter") -> t.Optional[str]:
- """Optionally might return extra information about a missing
- parameter.
-
- .. versionadded:: 2.0
- """
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- """Convert the value to the correct type. This is not called if
- the value is ``None`` (the missing value).
-
- This must accept string values from the command line, as well as
- values that are already the correct type. It may also convert
- other compatible types.
-
- The ``param`` and ``ctx`` arguments may be ``None`` in certain
- situations, such as when converting prompt input.
-
- If the value cannot be converted, call :meth:`fail` with a
- descriptive message.
-
- :param value: The value to convert.
- :param param: The parameter that is using this type to convert
- its value. May be ``None``.
- :param ctx: The current context that arrived at this value. May
- be ``None``.
- """
- return value
-
- def split_envvar_value(self, rv: str) -> t.Sequence[str]:
- """Given a value from an environment variable this splits it up
- into small chunks depending on the defined envvar list splitter.
-
- If the splitter is set to `None`, which means that whitespace splits,
- then leading and trailing whitespace is ignored. Otherwise, leading
- and trailing splitters usually lead to empty items being included.
- """
- return (rv or "").split(self.envvar_list_splitter)
-
- def fail(
- self,
- message: str,
- param: t.Optional["Parameter"] = None,
- ctx: t.Optional["Context"] = None,
- ) -> "t.NoReturn":
- """Helper method to fail with an invalid value message."""
- raise BadParameter(message, ctx=ctx, param=param)
-
- def shell_complete(
- self, ctx: "Context", param: "Parameter", incomplete: str
- ) -> t.List["CompletionItem"]:
- """Return a list of
- :class:`~click.shell_completion.CompletionItem` objects for the
- incomplete value. Most types do not provide completions, but
- some do, and this allows custom types to provide custom
- completions as well.
-
- :param ctx: Invocation context for this command.
- :param param: The parameter that is requesting completion.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- return []
-
-
-class CompositeParamType(ParamType):
- is_composite = True
-
- @property
- def arity(self) -> int: # type: ignore
- raise NotImplementedError()
-
-
-class FuncParamType(ParamType):
- def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None:
- self.name = func.__name__
- self.func = func
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict["func"] = self.func
- return info_dict
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- try:
- return self.func(value)
- except ValueError:
- try:
- value = str(value)
- except UnicodeError:
- value = value.decode("utf-8", "replace")
-
- self.fail(value, param, ctx)
-
-
-class UnprocessedParamType(ParamType):
- name = "text"
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- return value
-
- def __repr__(self) -> str:
- return "UNPROCESSED"
-
-
-class StringParamType(ParamType):
- name = "text"
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- if isinstance(value, bytes):
- enc = _get_argv_encoding()
- try:
- value = value.decode(enc)
- except UnicodeError:
- fs_enc = get_filesystem_encoding()
- if fs_enc != enc:
- try:
- value = value.decode(fs_enc)
- except UnicodeError:
- value = value.decode("utf-8", "replace")
- else:
- value = value.decode("utf-8", "replace")
- return value
- return str(value)
-
- def __repr__(self) -> str:
- return "STRING"
-
-
-class Choice(ParamType):
- """The choice type allows a value to be checked against a fixed set
- of supported values. All of these values have to be strings.
-
- You should only pass a list or tuple of choices. Other iterables
- (like generators) may lead to surprising results.
-
- The resulting value will always be one of the originally passed choices
- regardless of ``case_sensitive`` or any ``ctx.token_normalize_func``
- being specified.
-
- See :ref:`choice-opts` for an example.
-
- :param case_sensitive: Set to false to make choices case
- insensitive. Defaults to true.
- """
-
- name = "choice"
-
- def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None:
- self.choices = choices
- self.case_sensitive = case_sensitive
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict["choices"] = self.choices
- info_dict["case_sensitive"] = self.case_sensitive
- return info_dict
-
- def get_metavar(self, param: "Parameter") -> str:
- choices_str = "|".join(self.choices)
-
- # Use curly braces to indicate a required argument.
- if param.required and param.param_type_name == "argument":
- return f"{{{choices_str}}}"
-
- # Use square braces to indicate an option or optional argument.
- return f"[{choices_str}]"
-
- def get_missing_message(self, param: "Parameter") -> str:
- return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices))
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- # Match through normalization and case sensitivity
- # first do token_normalize_func, then lowercase
- # preserve original `value` to produce an accurate message in
- # `self.fail`
- normed_value = value
- normed_choices = {choice: choice for choice in self.choices}
-
- if ctx is not None and ctx.token_normalize_func is not None:
- normed_value = ctx.token_normalize_func(value)
- normed_choices = {
- ctx.token_normalize_func(normed_choice): original
- for normed_choice, original in normed_choices.items()
- }
-
- if not self.case_sensitive:
- normed_value = normed_value.casefold()
- normed_choices = {
- normed_choice.casefold(): original
- for normed_choice, original in normed_choices.items()
- }
-
- if normed_value in normed_choices:
- return normed_choices[normed_value]
-
- choices_str = ", ".join(map(repr, self.choices))
- self.fail(
- ngettext(
- "{value!r} is not {choice}.",
- "{value!r} is not one of {choices}.",
- len(self.choices),
- ).format(value=value, choice=choices_str, choices=choices_str),
- param,
- ctx,
- )
-
- def __repr__(self) -> str:
- return f"Choice({list(self.choices)})"
-
- def shell_complete(
- self, ctx: "Context", param: "Parameter", incomplete: str
- ) -> t.List["CompletionItem"]:
- """Complete choices that start with the incomplete value.
-
- :param ctx: Invocation context for this command.
- :param param: The parameter that is requesting completion.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- from click.shell_completion import CompletionItem
-
- str_choices = map(str, self.choices)
-
- if self.case_sensitive:
- matched = (c for c in str_choices if c.startswith(incomplete))
- else:
- incomplete = incomplete.lower()
- matched = (c for c in str_choices if c.lower().startswith(incomplete))
-
- return [CompletionItem(c) for c in matched]
-
-
-class DateTime(ParamType):
- """The DateTime type converts date strings into `datetime` objects.
-
- The format strings which are checked are configurable, but default to some
- common (non-timezone aware) ISO 8601 formats.
-
- When specifying *DateTime* formats, you should only pass a list or a tuple.
- Other iterables, like generators, may lead to surprising results.
-
- The format strings are processed using ``datetime.strptime``, and this
- consequently defines the format strings which are allowed.
-
- Parsing is tried using each format, in order, and the first format which
- parses successfully is used.
-
- :param formats: A list or tuple of date format strings, in the order in
- which they should be tried. Defaults to
- ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``,
- ``'%Y-%m-%d %H:%M:%S'``.
- """
-
- name = "datetime"
-
- def __init__(self, formats: t.Optional[t.Sequence[str]] = None):
- self.formats = formats or ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"]
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict["formats"] = self.formats
- return info_dict
-
- def get_metavar(self, param: "Parameter") -> str:
- return f"[{'|'.join(self.formats)}]"
-
- def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]:
- try:
- return datetime.strptime(value, format)
- except ValueError:
- return None
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- if isinstance(value, datetime):
- return value
-
- for format in self.formats:
- converted = self._try_to_convert_date(value, format)
-
- if converted is not None:
- return converted
-
- formats_str = ", ".join(map(repr, self.formats))
- self.fail(
- ngettext(
- "{value!r} does not match the format {format}.",
- "{value!r} does not match the formats {formats}.",
- len(self.formats),
- ).format(value=value, format=formats_str, formats=formats_str),
- param,
- ctx,
- )
-
- def __repr__(self) -> str:
- return "DateTime"
-
-
-class _NumberParamTypeBase(ParamType):
- _number_class: t.ClassVar[t.Type]
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- try:
- return self._number_class(value)
- except ValueError:
- self.fail(
- _("{value!r} is not a valid {number_type}.").format(
- value=value, number_type=self.name
- ),
- param,
- ctx,
- )
-
-
-class _NumberRangeBase(_NumberParamTypeBase):
- def __init__(
- self,
- min: t.Optional[float] = None,
- max: t.Optional[float] = None,
- min_open: bool = False,
- max_open: bool = False,
- clamp: bool = False,
- ) -> None:
- self.min = min
- self.max = max
- self.min_open = min_open
- self.max_open = max_open
- self.clamp = clamp
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict.update(
- min=self.min,
- max=self.max,
- min_open=self.min_open,
- max_open=self.max_open,
- clamp=self.clamp,
- )
- return info_dict
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- import operator
-
- rv = super().convert(value, param, ctx)
- lt_min: bool = self.min is not None and (
- operator.le if self.min_open else operator.lt
- )(rv, self.min)
- gt_max: bool = self.max is not None and (
- operator.ge if self.max_open else operator.gt
- )(rv, self.max)
-
- if self.clamp:
- if lt_min:
- return self._clamp(self.min, 1, self.min_open) # type: ignore
-
- if gt_max:
- return self._clamp(self.max, -1, self.max_open) # type: ignore
-
- if lt_min or gt_max:
- self.fail(
- _("{value} is not in the range {range}.").format(
- value=rv, range=self._describe_range()
- ),
- param,
- ctx,
- )
-
- return rv
-
- def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float:
- """Find the valid value to clamp to bound in the given
- direction.
-
- :param bound: The boundary value.
- :param dir: 1 or -1 indicating the direction to move.
- :param open: If true, the range does not include the bound.
- """
- raise NotImplementedError
-
- def _describe_range(self) -> str:
- """Describe the range for use in help text."""
- if self.min is None:
- op = "<" if self.max_open else "<="
- return f"x{op}{self.max}"
-
- if self.max is None:
- op = ">" if self.min_open else ">="
- return f"x{op}{self.min}"
-
- lop = "<" if self.min_open else "<="
- rop = "<" if self.max_open else "<="
- return f"{self.min}{lop}x{rop}{self.max}"
-
- def __repr__(self) -> str:
- clamp = " clamped" if self.clamp else ""
- return f"<{type(self).__name__} {self._describe_range()}{clamp}>"
-
-
-class IntParamType(_NumberParamTypeBase):
- name = "integer"
- _number_class = int
-
- def __repr__(self) -> str:
- return "INT"
-
-
-class IntRange(_NumberRangeBase, IntParamType):
- """Restrict an :data:`click.INT` value to a range of accepted
- values. See :ref:`ranges`.
-
- If ``min`` or ``max`` are not passed, any value is accepted in that
- direction. If ``min_open`` or ``max_open`` are enabled, the
- corresponding boundary is not included in the range.
-
- If ``clamp`` is enabled, a value outside the range is clamped to the
- boundary instead of failing.
-
- .. versionchanged:: 8.0
- Added the ``min_open`` and ``max_open`` parameters.
- """
-
- name = "integer range"
-
- def _clamp( # type: ignore
- self, bound: int, dir: "te.Literal[1, -1]", open: bool
- ) -> int:
- if not open:
- return bound
-
- return bound + dir
-
-
-class FloatParamType(_NumberParamTypeBase):
- name = "float"
- _number_class = float
-
- def __repr__(self) -> str:
- return "FLOAT"
-
-
-class FloatRange(_NumberRangeBase, FloatParamType):
- """Restrict a :data:`click.FLOAT` value to a range of accepted
- values. See :ref:`ranges`.
-
- If ``min`` or ``max`` are not passed, any value is accepted in that
- direction. If ``min_open`` or ``max_open`` are enabled, the
- corresponding boundary is not included in the range.
-
- If ``clamp`` is enabled, a value outside the range is clamped to the
- boundary instead of failing. This is not supported if either
- boundary is marked ``open``.
-
- .. versionchanged:: 8.0
- Added the ``min_open`` and ``max_open`` parameters.
- """
-
- name = "float range"
-
- def __init__(
- self,
- min: t.Optional[float] = None,
- max: t.Optional[float] = None,
- min_open: bool = False,
- max_open: bool = False,
- clamp: bool = False,
- ) -> None:
- super().__init__(
- min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp
- )
-
- if (min_open or max_open) and clamp:
- raise TypeError("Clamping is not supported for open bounds.")
-
- def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float:
- if not open:
- return bound
-
- # Could use Python 3.9's math.nextafter here, but clamping an
- # open float range doesn't seem to be particularly useful. It's
- # left up to the user to write a callback to do it if needed.
- raise RuntimeError("Clamping is not supported for open bounds.")
-
-
-class BoolParamType(ParamType):
- name = "boolean"
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- if value in {False, True}:
- return bool(value)
-
- norm = value.strip().lower()
-
- if norm in {"1", "true", "t", "yes", "y", "on"}:
- return True
-
- if norm in {"0", "false", "f", "no", "n", "off"}:
- return False
-
- self.fail(
- _("{value!r} is not a valid boolean.").format(value=value), param, ctx
- )
-
- def __repr__(self) -> str:
- return "BOOL"
-
-
-class UUIDParameterType(ParamType):
- name = "uuid"
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- import uuid
-
- if isinstance(value, uuid.UUID):
- return value
-
- value = value.strip()
-
- try:
- return uuid.UUID(value)
- except ValueError:
- self.fail(
- _("{value!r} is not a valid UUID.").format(value=value), param, ctx
- )
-
- def __repr__(self) -> str:
- return "UUID"
-
-
-class File(ParamType):
- """Declares a parameter to be a file for reading or writing. The file
- is automatically closed once the context tears down (after the command
- finished working).
-
- Files can be opened for reading or writing. The special value ``-``
- indicates stdin or stdout depending on the mode.
-
- By default, the file is opened for reading text data, but it can also be
- opened in binary mode or for writing. The encoding parameter can be used
- to force a specific encoding.
-
- The `lazy` flag controls if the file should be opened immediately or upon
- first IO. The default is to be non-lazy for standard input and output
- streams as well as files opened for reading, `lazy` otherwise. When opening a
- file lazily for reading, it is still opened temporarily for validation, but
- will not be held open until first IO. lazy is mainly useful when opening
- for writing to avoid creating the file until it is needed.
-
- Starting with Click 2.0, files can also be opened atomically in which
- case all writes go into a separate file in the same folder and upon
- completion the file will be moved over to the original location. This
- is useful if a file regularly read by other users is modified.
-
- See :ref:`file-args` for more information.
- """
-
- name = "filename"
- envvar_list_splitter = os.path.pathsep
-
- def __init__(
- self,
- mode: str = "r",
- encoding: t.Optional[str] = None,
- errors: t.Optional[str] = "strict",
- lazy: t.Optional[bool] = None,
- atomic: bool = False,
- ) -> None:
- self.mode = mode
- self.encoding = encoding
- self.errors = errors
- self.lazy = lazy
- self.atomic = atomic
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict.update(mode=self.mode, encoding=self.encoding)
- return info_dict
-
- def resolve_lazy_flag(self, value: t.Any) -> bool:
- if self.lazy is not None:
- return self.lazy
- if value == "-":
- return False
- elif "w" in self.mode:
- return True
- return False
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- try:
- if hasattr(value, "read") or hasattr(value, "write"):
- return value
-
- lazy = self.resolve_lazy_flag(value)
-
- if lazy:
- f: t.IO = t.cast(
- t.IO,
- LazyFile(
- value, self.mode, self.encoding, self.errors, atomic=self.atomic
- ),
- )
-
- if ctx is not None:
- ctx.call_on_close(f.close_intelligently) # type: ignore
-
- return f
-
- f, should_close = open_stream(
- value, self.mode, self.encoding, self.errors, atomic=self.atomic
- )
-
- # If a context is provided, we automatically close the file
- # at the end of the context execution (or flush out). If a
- # context does not exist, it's the caller's responsibility to
- # properly close the file. This for instance happens when the
- # type is used with prompts.
- if ctx is not None:
- if should_close:
- ctx.call_on_close(safecall(f.close))
- else:
- ctx.call_on_close(safecall(f.flush))
-
- return f
- except OSError as e: # noqa: B014
- self.fail(f"{os.fsdecode(value)!r}: {e.strerror}", param, ctx)
-
- def shell_complete(
- self, ctx: "Context", param: "Parameter", incomplete: str
- ) -> t.List["CompletionItem"]:
- """Return a special completion marker that tells the completion
- system to use the shell to provide file path completions.
-
- :param ctx: Invocation context for this command.
- :param param: The parameter that is requesting completion.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- from click.shell_completion import CompletionItem
-
- return [CompletionItem(incomplete, type="file")]
-
-
-class Path(ParamType):
- """The path type is similar to the :class:`File` type but it performs
- different checks. First of all, instead of returning an open file
- handle it returns just the filename. Secondly, it can perform various
- basic checks about what the file or directory should be.
-
- :param exists: if set to true, the file or directory needs to exist for
- this value to be valid. If this is not required and a
- file does indeed not exist, then all further checks are
- silently skipped.
- :param file_okay: controls if a file is a possible value.
- :param dir_okay: controls if a directory is a possible value.
- :param writable: if true, a writable check is performed.
- :param readable: if true, a readable check is performed.
- :param resolve_path: if this is true, then the path is fully resolved
- before the value is passed onwards. This means
- that it's absolute and symlinks are resolved. It
- will not expand a tilde-prefix, as this is
- supposed to be done by the shell only.
- :param allow_dash: If this is set to `True`, a single dash to indicate
- standard streams is permitted.
- :param path_type: Convert the incoming path value to this type. If
- ``None``, keep Python's default, which is ``str``. Useful to
- convert to :class:`pathlib.Path`.
-
- .. versionchanged:: 8.0
- Allow passing ``type=pathlib.Path``.
-
- .. versionchanged:: 6.0
- Added the ``allow_dash`` parameter.
- """
-
- envvar_list_splitter = os.path.pathsep
-
- def __init__(
- self,
- exists: bool = False,
- file_okay: bool = True,
- dir_okay: bool = True,
- writable: bool = False,
- readable: bool = True,
- resolve_path: bool = False,
- allow_dash: bool = False,
- path_type: t.Optional[t.Type] = None,
- ):
- self.exists = exists
- self.file_okay = file_okay
- self.dir_okay = dir_okay
- self.writable = writable
- self.readable = readable
- self.resolve_path = resolve_path
- self.allow_dash = allow_dash
- self.type = path_type
-
- if self.file_okay and not self.dir_okay:
- self.name = _("file")
- elif self.dir_okay and not self.file_okay:
- self.name = _("directory")
- else:
- self.name = _("path")
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict.update(
- exists=self.exists,
- file_okay=self.file_okay,
- dir_okay=self.dir_okay,
- writable=self.writable,
- readable=self.readable,
- allow_dash=self.allow_dash,
- )
- return info_dict
-
- def coerce_path_result(self, rv: t.Any) -> t.Any:
- if self.type is not None and not isinstance(rv, self.type):
- if self.type is str:
- rv = os.fsdecode(rv)
- elif self.type is bytes:
- rv = os.fsencode(rv)
- else:
- rv = self.type(rv)
-
- return rv
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- rv = value
-
- is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-")
-
- if not is_dash:
- if self.resolve_path:
- # realpath on Windows Python < 3.8 doesn't resolve symlinks
- if os.path.islink(rv):
- rv = os.readlink(rv)
-
- rv = os.path.realpath(rv)
-
- try:
- st = os.stat(rv)
- except OSError:
- if not self.exists:
- return self.coerce_path_result(rv)
- self.fail(
- _("{name} {filename!r} does not exist.").format(
- name=self.name.title(), filename=os.fsdecode(value)
- ),
- param,
- ctx,
- )
-
- if not self.file_okay and stat.S_ISREG(st.st_mode):
- self.fail(
- _("{name} {filename!r} is a file.").format(
- name=self.name.title(), filename=os.fsdecode(value)
- ),
- param,
- ctx,
- )
- if not self.dir_okay and stat.S_ISDIR(st.st_mode):
- self.fail(
- _("{name} {filename!r} is a directory.").format(
- name=self.name.title(), filename=os.fsdecode(value)
- ),
- param,
- ctx,
- )
- if self.writable and not os.access(value, os.W_OK):
- self.fail(
- _("{name} {filename!r} is not writable.").format(
- name=self.name.title(), filename=os.fsdecode(value)
- ),
- param,
- ctx,
- )
- if self.readable and not os.access(value, os.R_OK):
- self.fail(
- _("{name} {filename!r} is not readable.").format(
- name=self.name.title(), filename=os.fsdecode(value)
- ),
- param,
- ctx,
- )
-
- return self.coerce_path_result(rv)
-
- def shell_complete(
- self, ctx: "Context", param: "Parameter", incomplete: str
- ) -> t.List["CompletionItem"]:
- """Return a special completion marker that tells the completion
- system to use the shell to provide path completions for only
- directories or any paths.
-
- :param ctx: Invocation context for this command.
- :param param: The parameter that is requesting completion.
- :param incomplete: Value being completed. May be empty.
-
- .. versionadded:: 8.0
- """
- from click.shell_completion import CompletionItem
-
- type = "dir" if self.dir_okay and not self.file_okay else "file"
- return [CompletionItem(incomplete, type=type)]
-
-
-class Tuple(CompositeParamType):
- """The default behavior of Click is to apply a type on a value directly.
- This works well in most cases, except for when `nargs` is set to a fixed
- count and different types should be used for different items. In this
- case the :class:`Tuple` type can be used. This type can only be used
- if `nargs` is set to a fixed number.
-
- For more information see :ref:`tuple-type`.
-
- This can be selected by using a Python tuple literal as a type.
-
- :param types: a list of types that should be used for the tuple items.
- """
-
- def __init__(self, types: t.Sequence[t.Union[t.Type, ParamType]]) -> None:
- self.types = [convert_type(ty) for ty in types]
-
- def to_info_dict(self) -> t.Dict[str, t.Any]:
- info_dict = super().to_info_dict()
- info_dict["types"] = [t.to_info_dict() for t in self.types]
- return info_dict
-
- @property
- def name(self) -> str: # type: ignore
- return f"<{' '.join(ty.name for ty in self.types)}>"
-
- @property
- def arity(self) -> int: # type: ignore
- return len(self.types)
-
- def convert(
- self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"]
- ) -> t.Any:
- len_type = len(self.types)
- len_value = len(value)
-
- if len_value != len_type:
- self.fail(
- ngettext(
- "{len_type} values are required, but {len_value} was given.",
- "{len_type} values are required, but {len_value} were given.",
- len_value,
- ).format(len_type=len_type, len_value=len_value),
- param=param,
- ctx=ctx,
- )
-
- return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value))
-
-
-def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType:
- """Find the most appropriate :class:`ParamType` for the given Python
- type. If the type isn't provided, it can be inferred from a default
- value.
- """
- guessed_type = False
-
- if ty is None and default is not None:
- if isinstance(default, (tuple, list)):
- # If the default is empty, ty will remain None and will
- # return STRING.
- if default:
- item = default[0]
-
- # A tuple of tuples needs to detect the inner types.
- # Can't call convert recursively because that would
- # incorrectly unwind the tuple to a single type.
- if isinstance(item, (tuple, list)):
- ty = tuple(map(type, item))
- else:
- ty = type(item)
- else:
- ty = type(default)
-
- guessed_type = True
-
- if isinstance(ty, tuple):
- return Tuple(ty)
-
- if isinstance(ty, ParamType):
- return ty
-
- if ty is str or ty is None:
- return STRING
-
- if ty is int:
- return INT
-
- if ty is float:
- return FLOAT
-
- if ty is bool:
- return BOOL
-
- if guessed_type:
- return STRING
-
- if __debug__:
- try:
- if issubclass(ty, ParamType):
- raise AssertionError(
- f"Attempted to use an uninstantiated parameter type ({ty})."
- )
- except TypeError:
- # ty is an instance (correct), so issubclass fails.
- pass
-
- return FuncParamType(ty)
-
-
-#: A dummy parameter type that just does nothing. From a user's
-#: perspective this appears to just be the same as `STRING` but
-#: internally no string conversion takes place if the input was bytes.
-#: This is usually useful when working with file paths as they can
-#: appear in bytes and unicode.
-#:
-#: For path related uses the :class:`Path` type is a better choice but
-#: there are situations where an unprocessed type is useful which is why
-#: it is is provided.
-#:
-#: .. versionadded:: 4.0
-UNPROCESSED = UnprocessedParamType()
-
-#: A unicode string parameter type which is the implicit default. This
-#: can also be selected by using ``str`` as type.
-STRING = StringParamType()
-
-#: An integer parameter. This can also be selected by using ``int`` as
-#: type.
-INT = IntParamType()
-
-#: A floating point value parameter. This can also be selected by using
-#: ``float`` as type.
-FLOAT = FloatParamType()
-
-#: A boolean parameter. This is the default for boolean flags. This can
-#: also be selected by using ``bool`` as a type.
-BOOL = BoolParamType()
-
-#: A UUID parameter.
-UUID = UUIDParameterType()
diff --git a/venv/lib/python3.9/site-packages/click/utils.py b/venv/lib/python3.9/site-packages/click/utils.py
deleted file mode 100644
index 91a372d..0000000
--- a/venv/lib/python3.9/site-packages/click/utils.py
+++ /dev/null
@@ -1,579 +0,0 @@
-import os
-import sys
-import typing as t
-from functools import update_wrapper
-from types import ModuleType
-
-from ._compat import _default_text_stderr
-from ._compat import _default_text_stdout
-from ._compat import _find_binary_writer
-from ._compat import auto_wrap_for_ansi
-from ._compat import binary_streams
-from ._compat import get_filesystem_encoding
-from ._compat import open_stream
-from ._compat import should_strip_ansi
-from ._compat import strip_ansi
-from ._compat import text_streams
-from ._compat import WIN
-from .globals import resolve_color_default
-
-if t.TYPE_CHECKING:
- import typing_extensions as te
-
-F = t.TypeVar("F", bound=t.Callable[..., t.Any])
-
-
-def _posixify(name: str) -> str:
- return "-".join(name.split()).lower()
-
-
-def safecall(func: F) -> F:
- """Wraps a function so that it swallows exceptions."""
-
- def wrapper(*args, **kwargs): # type: ignore
- try:
- return func(*args, **kwargs)
- except Exception:
- pass
-
- return update_wrapper(t.cast(F, wrapper), func)
-
-
-def make_str(value: t.Any) -> str:
- """Converts a value into a valid string."""
- if isinstance(value, bytes):
- try:
- return value.decode(get_filesystem_encoding())
- except UnicodeError:
- return value.decode("utf-8", "replace")
- return str(value)
-
-
-def make_default_short_help(help: str, max_length: int = 45) -> str:
- """Returns a condensed version of help string."""
- # Consider only the first paragraph.
- paragraph_end = help.find("\n\n")
-
- if paragraph_end != -1:
- help = help[:paragraph_end]
-
- # Collapse newlines, tabs, and spaces.
- words = help.split()
-
- if not words:
- return ""
-
- # The first paragraph started with a "no rewrap" marker, ignore it.
- if words[0] == "\b":
- words = words[1:]
-
- total_length = 0
- last_index = len(words) - 1
-
- for i, word in enumerate(words):
- total_length += len(word) + (i > 0)
-
- if total_length > max_length: # too long, truncate
- break
-
- if word[-1] == ".": # sentence end, truncate without "..."
- return " ".join(words[: i + 1])
-
- if total_length == max_length and i != last_index:
- break # not at sentence end, truncate with "..."
- else:
- return " ".join(words) # no truncation needed
-
- # Account for the length of the suffix.
- total_length += len("...")
-
- # remove words until the length is short enough
- while i > 0:
- total_length -= len(words[i]) + (i > 0)
-
- if total_length <= max_length:
- break
-
- i -= 1
-
- return " ".join(words[:i]) + "..."
-
-
-class LazyFile:
- """A lazy file works like a regular file but it does not fully open
- the file but it does perform some basic checks early to see if the
- filename parameter does make sense. This is useful for safely opening
- files for writing.
- """
-
- def __init__(
- self,
- filename: str,
- mode: str = "r",
- encoding: t.Optional[str] = None,
- errors: t.Optional[str] = "strict",
- atomic: bool = False,
- ):
- self.name = filename
- self.mode = mode
- self.encoding = encoding
- self.errors = errors
- self.atomic = atomic
- self._f: t.Optional[t.IO]
-
- if filename == "-":
- self._f, self.should_close = open_stream(filename, mode, encoding, errors)
- else:
- if "r" in mode:
- # Open and close the file in case we're opening it for
- # reading so that we can catch at least some errors in
- # some cases early.
- open(filename, mode).close()
- self._f = None
- self.should_close = True
-
- def __getattr__(self, name: str) -> t.Any:
- return getattr(self.open(), name)
-
- def __repr__(self) -> str:
- if self._f is not None:
- return repr(self._f)
- return f""
-
- def open(self) -> t.IO:
- """Opens the file if it's not yet open. This call might fail with
- a :exc:`FileError`. Not handling this error will produce an error
- that Click shows.
- """
- if self._f is not None:
- return self._f
- try:
- rv, self.should_close = open_stream(
- self.name, self.mode, self.encoding, self.errors, atomic=self.atomic
- )
- except OSError as e: # noqa: E402
- from .exceptions import FileError
-
- raise FileError(self.name, hint=e.strerror)
- self._f = rv
- return rv
-
- def close(self) -> None:
- """Closes the underlying file, no matter what."""
- if self._f is not None:
- self._f.close()
-
- def close_intelligently(self) -> None:
- """This function only closes the file if it was opened by the lazy
- file wrapper. For instance this will never close stdin.
- """
- if self.should_close:
- self.close()
-
- def __enter__(self) -> "LazyFile":
- return self
-
- def __exit__(self, exc_type, exc_value, tb): # type: ignore
- self.close_intelligently()
-
- def __iter__(self) -> t.Iterator[t.AnyStr]:
- self.open()
- return iter(self._f) # type: ignore
-
-
-class KeepOpenFile:
- def __init__(self, file: t.IO) -> None:
- self._file = file
-
- def __getattr__(self, name: str) -> t.Any:
- return getattr(self._file, name)
-
- def __enter__(self) -> "KeepOpenFile":
- return self
-
- def __exit__(self, exc_type, exc_value, tb): # type: ignore
- pass
-
- def __repr__(self) -> str:
- return repr(self._file)
-
- def __iter__(self) -> t.Iterator[t.AnyStr]:
- return iter(self._file)
-
-
-def echo(
- message: t.Optional[t.Any] = None,
- file: t.Optional[t.IO] = None,
- nl: bool = True,
- err: bool = False,
- color: t.Optional[bool] = None,
-) -> None:
- """Print a message and newline to stdout or a file. This should be
- used instead of :func:`print` because it provides better support
- for different data, files, and environments.
-
- Compared to :func:`print`, this does the following:
-
- - Ensures that the output encoding is not misconfigured on Linux.
- - Supports Unicode in the Windows console.
- - Supports writing to binary outputs, and supports writing bytes
- to text outputs.
- - Supports colors and styles on Windows.
- - Removes ANSI color and style codes if the output does not look
- like an interactive terminal.
- - Always flushes the output.
-
- :param message: The string or bytes to output. Other objects are
- converted to strings.
- :param file: The file to write to. Defaults to ``stdout``.
- :param err: Write to ``stderr`` instead of ``stdout``.
- :param nl: Print a newline after the message. Enabled by default.
- :param color: Force showing or hiding colors and other styles. By
- default Click will remove color if the output does not look like
- an interactive terminal.
-
- .. versionchanged:: 6.0
- Support Unicode output on the Windows console. Click does not
- modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()``
- will still not support Unicode.
-
- .. versionchanged:: 4.0
- Added the ``color`` parameter.
-
- .. versionadded:: 3.0
- Added the ``err`` parameter.
-
- .. versionchanged:: 2.0
- Support colors on Windows if colorama is installed.
- """
- if file is None:
- if err:
- file = _default_text_stderr()
- else:
- file = _default_text_stdout()
-
- # Convert non bytes/text into the native string type.
- if message is not None and not isinstance(message, (str, bytes, bytearray)):
- out: t.Optional[t.Union[str, bytes]] = str(message)
- else:
- out = message
-
- if nl:
- out = out or ""
- if isinstance(out, str):
- out += "\n"
- else:
- out += b"\n"
-
- if not out:
- file.flush()
- return
-
- # If there is a message and the value looks like bytes, we manually
- # need to find the binary stream and write the message in there.
- # This is done separately so that most stream types will work as you
- # would expect. Eg: you can write to StringIO for other cases.
- if isinstance(out, (bytes, bytearray)):
- binary_file = _find_binary_writer(file)
-
- if binary_file is not None:
- file.flush()
- binary_file.write(out)
- binary_file.flush()
- return
-
- # ANSI style code support. For no message or bytes, nothing happens.
- # When outputting to a file instead of a terminal, strip codes.
- else:
- color = resolve_color_default(color)
-
- if should_strip_ansi(file, color):
- out = strip_ansi(out)
- elif WIN:
- if auto_wrap_for_ansi is not None:
- file = auto_wrap_for_ansi(file) # type: ignore
- elif not color:
- out = strip_ansi(out)
-
- file.write(out) # type: ignore
- file.flush()
-
-
-def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO:
- """Returns a system stream for byte processing.
-
- :param name: the name of the stream to open. Valid names are ``'stdin'``,
- ``'stdout'`` and ``'stderr'``
- """
- opener = binary_streams.get(name)
- if opener is None:
- raise TypeError(f"Unknown standard stream '{name}'")
- return opener()
-
-
-def get_text_stream(
- name: "te.Literal['stdin', 'stdout', 'stderr']",
- encoding: t.Optional[str] = None,
- errors: t.Optional[str] = "strict",
-) -> t.TextIO:
- """Returns a system stream for text processing. This usually returns
- a wrapped stream around a binary stream returned from
- :func:`get_binary_stream` but it also can take shortcuts for already
- correctly configured streams.
-
- :param name: the name of the stream to open. Valid names are ``'stdin'``,
- ``'stdout'`` and ``'stderr'``
- :param encoding: overrides the detected default encoding.
- :param errors: overrides the default error mode.
- """
- opener = text_streams.get(name)
- if opener is None:
- raise TypeError(f"Unknown standard stream '{name}'")
- return opener(encoding, errors)
-
-
-def open_file(
- filename: str,
- mode: str = "r",
- encoding: t.Optional[str] = None,
- errors: t.Optional[str] = "strict",
- lazy: bool = False,
- atomic: bool = False,
-) -> t.IO:
- """This is similar to how the :class:`File` works but for manual
- usage. Files are opened non lazy by default. This can open regular
- files as well as stdin/stdout if ``'-'`` is passed.
-
- If stdin/stdout is returned the stream is wrapped so that the context
- manager will not close the stream accidentally. This makes it possible
- to always use the function like this without having to worry to
- accidentally close a standard stream::
-
- with open_file(filename) as f:
- ...
-
- .. versionadded:: 3.0
-
- :param filename: the name of the file to open (or ``'-'`` for stdin/stdout).
- :param mode: the mode in which to open the file.
- :param encoding: the encoding to use.
- :param errors: the error handling for this file.
- :param lazy: can be flipped to true to open the file lazily.
- :param atomic: in atomic mode writes go into a temporary file and it's
- moved on close.
- """
- if lazy:
- return t.cast(t.IO, LazyFile(filename, mode, encoding, errors, atomic=atomic))
- f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic)
- if not should_close:
- f = t.cast(t.IO, KeepOpenFile(f))
- return f
-
-
-def get_os_args() -> t.Sequence[str]:
- """Returns the argument part of ``sys.argv``, removing the first
- value which is the name of the script.
-
- .. deprecated:: 8.0
- Will be removed in Click 8.1. Access ``sys.argv[1:]`` directly
- instead.
- """
- import warnings
-
- warnings.warn(
- "'get_os_args' is deprecated and will be removed in Click 8.1."
- " Access 'sys.argv[1:]' directly instead.",
- DeprecationWarning,
- stacklevel=2,
- )
- return sys.argv[1:]
-
-
-def format_filename(
- filename: t.Union[str, bytes, os.PathLike], shorten: bool = False
-) -> str:
- """Formats a filename for user display. The main purpose of this
- function is to ensure that the filename can be displayed at all. This
- will decode the filename to unicode if necessary in a way that it will
- not fail. Optionally, it can shorten the filename to not include the
- full path to the filename.
-
- :param filename: formats a filename for UI display. This will also convert
- the filename into unicode without failing.
- :param shorten: this optionally shortens the filename to strip of the
- path that leads up to it.
- """
- if shorten:
- filename = os.path.basename(filename)
-
- return os.fsdecode(filename)
-
-
-def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str:
- r"""Returns the config folder for the application. The default behavior
- is to return whatever is most appropriate for the operating system.
-
- To give you an idea, for an app called ``"Foo Bar"``, something like
- the following folders could be returned:
-
- Mac OS X:
- ``~/Library/Application Support/Foo Bar``
- Mac OS X (POSIX):
- ``~/.foo-bar``
- Unix:
- ``~/.config/foo-bar``
- Unix (POSIX):
- ``~/.foo-bar``
- Windows (roaming):
- ``C:\Users\\AppData\Roaming\Foo Bar``
- Windows (not roaming):
- ``C:\Users\\AppData\Local\Foo Bar``
-
- .. versionadded:: 2.0
-
- :param app_name: the application name. This should be properly capitalized
- and can contain whitespace.
- :param roaming: controls if the folder should be roaming or not on Windows.
- Has no affect otherwise.
- :param force_posix: if this is set to `True` then on any POSIX system the
- folder will be stored in the home folder with a leading
- dot instead of the XDG config home or darwin's
- application support folder.
- """
- if WIN:
- key = "APPDATA" if roaming else "LOCALAPPDATA"
- folder = os.environ.get(key)
- if folder is None:
- folder = os.path.expanduser("~")
- return os.path.join(folder, app_name)
- if force_posix:
- return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}"))
- if sys.platform == "darwin":
- return os.path.join(
- os.path.expanduser("~/Library/Application Support"), app_name
- )
- return os.path.join(
- os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")),
- _posixify(app_name),
- )
-
-
-class PacifyFlushWrapper:
- """This wrapper is used to catch and suppress BrokenPipeErrors resulting
- from ``.flush()`` being called on broken pipe during the shutdown/final-GC
- of the Python interpreter. Notably ``.flush()`` is always called on
- ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any
- other cleanup code, and the case where the underlying file is not a broken
- pipe, all calls and attributes are proxied.
- """
-
- def __init__(self, wrapped: t.IO) -> None:
- self.wrapped = wrapped
-
- def flush(self) -> None:
- try:
- self.wrapped.flush()
- except OSError as e:
- import errno
-
- if e.errno != errno.EPIPE:
- raise
-
- def __getattr__(self, attr: str) -> t.Any:
- return getattr(self.wrapped, attr)
-
-
-def _detect_program_name(
- path: t.Optional[str] = None, _main: ModuleType = sys.modules["__main__"]
-) -> str:
- """Determine the command used to run the program, for use in help
- text. If a file or entry point was executed, the file name is
- returned. If ``python -m`` was used to execute a module or package,
- ``python -m name`` is returned.
-
- This doesn't try to be too precise, the goal is to give a concise
- name for help text. Files are only shown as their name without the
- path. ``python`` is only shown for modules, and the full path to
- ``sys.executable`` is not shown.
-
- :param path: The Python file being executed. Python puts this in
- ``sys.argv[0]``, which is used by default.
- :param _main: The ``__main__`` module. This should only be passed
- during internal testing.
-
- .. versionadded:: 8.0
- Based on command args detection in the Werkzeug reloader.
-
- :meta private:
- """
- if not path:
- path = sys.argv[0]
-
- # The value of __package__ indicates how Python was called. It may
- # not exist if a setuptools script is installed as an egg. It may be
- # set incorrectly for entry points created with pip on Windows.
- if getattr(_main, "__package__", None) is None or (
- os.name == "nt"
- and _main.__package__ == ""
- and not os.path.exists(path)
- and os.path.exists(f"{path}.exe")
- ):
- # Executed a file, like "python app.py".
- return os.path.basename(path)
-
- # Executed a module, like "python -m example".
- # Rewritten by Python from "-m script" to "/path/to/script.py".
- # Need to look at main module to determine how it was executed.
- py_module = t.cast(str, _main.__package__)
- name = os.path.splitext(os.path.basename(path))[0]
-
- # A submodule like "example.cli".
- if name != "__main__":
- py_module = f"{py_module}.{name}"
-
- return f"python -m {py_module.lstrip('.')}"
-
-
-def _expand_args(
- args: t.Iterable[str],
- *,
- user: bool = True,
- env: bool = True,
- glob_recursive: bool = True,
-) -> t.List[str]:
- """Simulate Unix shell expansion with Python functions.
-
- See :func:`glob.glob`, :func:`os.path.expanduser`, and
- :func:`os.path.expandvars`.
-
- This intended for use on Windows, where the shell does not do any
- expansion. It may not exactly match what a Unix shell would do.
-
- :param args: List of command line arguments to expand.
- :param user: Expand user home directory.
- :param env: Expand environment variables.
- :param glob_recursive: ``**`` matches directories recursively.
-
- .. versionadded:: 8.0
-
- :meta private:
- """
- from glob import glob
-
- out = []
-
- for arg in args:
- if user:
- arg = os.path.expanduser(arg)
-
- if env:
- arg = os.path.expandvars(arg)
-
- matches = glob(arg, recursive=glob_recursive)
-
- if not matches:
- out.append(arg)
- else:
- out.extend(matches)
-
- return out
diff --git a/venv/lib/python3.9/site-packages/easy_install.py b/venv/lib/python3.9/site-packages/easy_install.py
deleted file mode 100644
index d87e984..0000000
--- a/venv/lib/python3.9/site-packages/easy_install.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""Run the EasyInstall command"""
-
-if __name__ == '__main__':
- from setuptools.command.easy_install import main
- main()
diff --git a/venv/lib/python3.9/site-packages/flask/__init__.py b/venv/lib/python3.9/site-packages/flask/__init__.py
deleted file mode 100644
index c5da045..0000000
--- a/venv/lib/python3.9/site-packages/flask/__init__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from markupsafe import escape
-from markupsafe import Markup
-from werkzeug.exceptions import abort as abort
-from werkzeug.utils import redirect as redirect
-
-from . import json as json
-from .app import Flask as Flask
-from .app import Request as Request
-from .app import Response as Response
-from .blueprints import Blueprint as Blueprint
-from .config import Config as Config
-from .ctx import after_this_request as after_this_request
-from .ctx import copy_current_request_context as copy_current_request_context
-from .ctx import has_app_context as has_app_context
-from .ctx import has_request_context as has_request_context
-from .globals import _app_ctx_stack as _app_ctx_stack
-from .globals import _request_ctx_stack as _request_ctx_stack
-from .globals import current_app as current_app
-from .globals import g as g
-from .globals import request as request
-from .globals import session as session
-from .helpers import flash as flash
-from .helpers import get_flashed_messages as get_flashed_messages
-from .helpers import get_template_attribute as get_template_attribute
-from .helpers import make_response as make_response
-from .helpers import safe_join as safe_join
-from .helpers import send_file as send_file
-from .helpers import send_from_directory as send_from_directory
-from .helpers import stream_with_context as stream_with_context
-from .helpers import url_for as url_for
-from .json import jsonify as jsonify
-from .signals import appcontext_popped as appcontext_popped
-from .signals import appcontext_pushed as appcontext_pushed
-from .signals import appcontext_tearing_down as appcontext_tearing_down
-from .signals import before_render_template as before_render_template
-from .signals import got_request_exception as got_request_exception
-from .signals import message_flashed as message_flashed
-from .signals import request_finished as request_finished
-from .signals import request_started as request_started
-from .signals import request_tearing_down as request_tearing_down
-from .signals import signals_available as signals_available
-from .signals import template_rendered as template_rendered
-from .templating import render_template as render_template
-from .templating import render_template_string as render_template_string
-
-__version__ = "2.0.1"
diff --git a/venv/lib/python3.9/site-packages/flask/__main__.py b/venv/lib/python3.9/site-packages/flask/__main__.py
deleted file mode 100644
index 4e28416..0000000
--- a/venv/lib/python3.9/site-packages/flask/__main__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .cli import main
-
-main()
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/__init__.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/__init__.cpython-39.pyc
deleted file mode 100644
index f28046c..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/__init__.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/__main__.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/__main__.cpython-39.pyc
deleted file mode 100644
index 2f9696f..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/__main__.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/app.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/app.cpython-39.pyc
deleted file mode 100644
index 0e6e08b..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/app.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/blueprints.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/blueprints.cpython-39.pyc
deleted file mode 100644
index 89c5eda..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/blueprints.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/cli.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/cli.cpython-39.pyc
deleted file mode 100644
index 578dd23..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/cli.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/config.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/config.cpython-39.pyc
deleted file mode 100644
index 0e469ae..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/config.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/ctx.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/ctx.cpython-39.pyc
deleted file mode 100644
index 23cd77f..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/ctx.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/debughelpers.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/debughelpers.cpython-39.pyc
deleted file mode 100644
index edc86eb..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/debughelpers.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/globals.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/globals.cpython-39.pyc
deleted file mode 100644
index ecc0f0b..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/globals.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/helpers.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/helpers.cpython-39.pyc
deleted file mode 100644
index 450d440..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/helpers.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/logging.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/logging.cpython-39.pyc
deleted file mode 100644
index 594c3ab..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/logging.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/scaffold.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/scaffold.cpython-39.pyc
deleted file mode 100644
index 190f931..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/scaffold.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/sessions.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/sessions.cpython-39.pyc
deleted file mode 100644
index e1db424..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/sessions.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/signals.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/signals.cpython-39.pyc
deleted file mode 100644
index 36bf1ec..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/signals.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/templating.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/templating.cpython-39.pyc
deleted file mode 100644
index 5b6877b..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/templating.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/testing.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/testing.cpython-39.pyc
deleted file mode 100644
index 7b3ed54..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/testing.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/typing.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/typing.cpython-39.pyc
deleted file mode 100644
index fd2ccf9..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/typing.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/views.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/views.cpython-39.pyc
deleted file mode 100644
index 34d2ee6..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/views.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/__pycache__/wrappers.cpython-39.pyc b/venv/lib/python3.9/site-packages/flask/__pycache__/wrappers.cpython-39.pyc
deleted file mode 100644
index c741282..0000000
Binary files a/venv/lib/python3.9/site-packages/flask/__pycache__/wrappers.cpython-39.pyc and /dev/null differ
diff --git a/venv/lib/python3.9/site-packages/flask/app.py b/venv/lib/python3.9/site-packages/flask/app.py
deleted file mode 100644
index 3abce3c..0000000
--- a/venv/lib/python3.9/site-packages/flask/app.py
+++ /dev/null
@@ -1,2088 +0,0 @@
-import functools
-import inspect
-import logging
-import os
-import sys
-import typing as t
-import weakref
-from datetime import timedelta
-from itertools import chain
-from threading import Lock
-from types import TracebackType
-
-from werkzeug.datastructures import Headers
-from werkzeug.datastructures import ImmutableDict
-from werkzeug.exceptions import BadRequest
-from werkzeug.exceptions import BadRequestKeyError
-from werkzeug.exceptions import HTTPException
-from werkzeug.exceptions import InternalServerError
-from werkzeug.local import ContextVar
-from werkzeug.routing import BuildError
-from werkzeug.routing import Map
-from werkzeug.routing import MapAdapter
-from werkzeug.routing import RequestRedirect
-from werkzeug.routing import RoutingException
-from werkzeug.routing import Rule
-from werkzeug.wrappers import Response as BaseResponse
-
-from . import cli
-from . import json
-from .config import Config
-from .config import ConfigAttribute
-from .ctx import _AppCtxGlobals
-from .ctx import AppContext
-from .ctx import RequestContext
-from .globals import _request_ctx_stack
-from .globals import g
-from .globals import request
-from .globals import session
-from .helpers import _split_blueprint_path
-from .helpers import get_debug_flag
-from .helpers import get_env
-from .helpers import get_flashed_messages
-from .helpers import get_load_dotenv
-from .helpers import locked_cached_property
-from .helpers import url_for
-from .json import jsonify
-from .logging import create_logger
-from .scaffold import _endpoint_from_view_func
-from .scaffold import _sentinel
-from .scaffold import find_package
-from .scaffold import Scaffold
-from .scaffold import setupmethod
-from .sessions import SecureCookieSessionInterface
-from .signals import appcontext_tearing_down
-from .signals import got_request_exception
-from .signals import request_finished
-from .signals import request_started
-from .signals import request_tearing_down
-from .templating import DispatchingJinjaLoader
-from .templating import Environment
-from .typing import AfterRequestCallable
-from .typing import BeforeRequestCallable
-from .typing import ErrorHandlerCallable
-from .typing import ResponseReturnValue
-from .typing import TeardownCallable
-from .typing import TemplateContextProcessorCallable
-from .typing import TemplateFilterCallable
-from .typing import TemplateGlobalCallable
-from .typing import TemplateTestCallable
-from .typing import URLDefaultCallable
-from .typing import URLValuePreprocessorCallable
-from .wrappers import Request
-from .wrappers import Response
-
-if t.TYPE_CHECKING:
- import typing_extensions as te
- from .blueprints import Blueprint
- from .testing import FlaskClient
- from .testing import FlaskCliRunner
-
-if sys.version_info >= (3, 8):
- iscoroutinefunction = inspect.iscoroutinefunction
-else:
-
- def iscoroutinefunction(func: t.Any) -> bool:
- while inspect.ismethod(func):
- func = func.__func__
-
- while isinstance(func, functools.partial):
- func = func.func
-
- return inspect.iscoroutinefunction(func)
-
-
-def _make_timedelta(value: t.Optional[timedelta]) -> t.Optional[timedelta]:
- if value is None or isinstance(value, timedelta):
- return value
-
- return timedelta(seconds=value)
-
-
-class Flask(Scaffold):
- """The flask object implements a WSGI application and acts as the central
- object. It is passed the name of the module or package of the
- application. Once it is created it will act as a central registry for
- the view functions, the URL rules, template configuration and much more.
-
- The name of the package is used to resolve resources from inside the
- package or the folder the module is contained in depending on if the
- package parameter resolves to an actual python package (a folder with
- an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).
-
- For more information about resource loading, see :func:`open_resource`.
-
- Usually you create a :class:`Flask` instance in your main module or
- in the :file:`__init__.py` file of your package like this::
-
- from flask import Flask
- app = Flask(__name__)
-
- .. admonition:: About the First Parameter
-
- The idea of the first parameter is to give Flask an idea of what
- belongs to your application. This name is used to find resources
- on the filesystem, can be used by extensions to improve debugging
- information and a lot more.
-
- So it's important what you provide there. If you are using a single
- module, `__name__` is always the correct value. If you however are
- using a package, it's usually recommended to hardcode the name of
- your package there.
-
- For example if your application is defined in :file:`yourapplication/app.py`
- you should create it with one of the two versions below::
-
- app = Flask('yourapplication')
- app = Flask(__name__.split('.')[0])
-
- Why is that? The application will work even with `__name__`, thanks
- to how resources are looked up. However it will make debugging more
- painful. Certain extensions can make assumptions based on the
- import name of your application. For example the Flask-SQLAlchemy
- extension will look for the code in your application that triggered
- an SQL query in debug mode. If the import name is not properly set
- up, that debugging information is lost. (For example it would only
- pick up SQL queries in `yourapplication.app` and not
- `yourapplication.views.frontend`)
-
- .. versionadded:: 0.7
- The `static_url_path`, `static_folder`, and `template_folder`
- parameters were added.
-
- .. versionadded:: 0.8
- The `instance_path` and `instance_relative_config` parameters were
- added.
-
- .. versionadded:: 0.11
- The `root_path` parameter was added.
-
- .. versionadded:: 1.0
- The ``host_matching`` and ``static_host`` parameters were added.
-
- .. versionadded:: 1.0
- The ``subdomain_matching`` parameter was added. Subdomain
- matching needs to be enabled manually now. Setting
- :data:`SERVER_NAME` does not implicitly enable it.
-
- :param import_name: the name of the application package
- :param static_url_path: can be used to specify a different path for the
- static files on the web. Defaults to the name
- of the `static_folder` folder.
- :param static_folder: The folder with static files that is served at
- ``static_url_path``. Relative to the application ``root_path``
- or an absolute path. Defaults to ``'static'``.
- :param static_host: the host to use when adding the static route.
- Defaults to None. Required when using ``host_matching=True``
- with a ``static_folder`` configured.
- :param host_matching: set ``url_map.host_matching`` attribute.
- Defaults to False.
- :param subdomain_matching: consider the subdomain relative to
- :data:`SERVER_NAME` when matching routes. Defaults to False.
- :param template_folder: the folder that contains the templates that should
- be used by the application. Defaults to
- ``'templates'`` folder in the root path of the
- application.
- :param instance_path: An alternative instance path for the application.
- By default the folder ``'instance'`` next to the
- package or module is assumed to be the instance
- path.
- :param instance_relative_config: if set to ``True`` relative filenames
- for loading the config are assumed to
- be relative to the instance path instead
- of the application root.
- :param root_path: The path to the root of the application files.
- This should only be set manually when it can't be detected
- automatically, such as for namespace packages.
- """
-
- #: The class that is used for request objects. See :class:`~flask.Request`
- #: for more information.
- request_class = Request
-
- #: The class that is used for response objects. See
- #: :class:`~flask.Response` for more information.
- response_class = Response
-
- #: The class that is used for the Jinja environment.
- #:
- #: .. versionadded:: 0.11
- jinja_environment = Environment
-
- #: The class that is used for the :data:`~flask.g` instance.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Store arbitrary attributes on flask.g.
- #: 2. Add a property for lazy per-request database connectors.
- #: 3. Return None instead of AttributeError on unexpected attributes.
- #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
- #:
- #: In Flask 0.9 this property was called `request_globals_class` but it
- #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the
- #: flask.g object is now application context scoped.
- #:
- #: .. versionadded:: 0.10
- app_ctx_globals_class = _AppCtxGlobals
-
- #: The class that is used for the ``config`` attribute of this app.
- #: Defaults to :class:`~flask.Config`.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Default values for certain config options.
- #: 2. Access to config values through attributes in addition to keys.
- #:
- #: .. versionadded:: 0.11
- config_class = Config
-
- #: The testing flag. Set this to ``True`` to enable the test mode of
- #: Flask extensions (and in the future probably also Flask itself).
- #: For example this might activate test helpers that have an
- #: additional runtime cost which should not be enabled by default.
- #:
- #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the
- #: default it's implicitly enabled.
- #:
- #: This attribute can also be configured from the config with the
- #: ``TESTING`` configuration key. Defaults to ``False``.
- testing = ConfigAttribute("TESTING")
-
- #: If a secret key is set, cryptographic components can use this to
- #: sign cookies and other things. Set this to a complex random value
- #: when you want to use the secure cookie for instance.
- #:
- #: This attribute can also be configured from the config with the
- #: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
- secret_key = ConfigAttribute("SECRET_KEY")
-
- #: The secure cookie uses this for the name of the session cookie.
- #:
- #: This attribute can also be configured from the config with the
- #: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
- session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME")
-
- #: A :class:`~datetime.timedelta` which is used to set the expiration
- #: date of a permanent session. The default is 31 days which makes a
- #: permanent session survive for roughly one month.
- #:
- #: This attribute can also be configured from the config with the
- #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to
- #: ``timedelta(days=31)``
- permanent_session_lifetime = ConfigAttribute(
- "PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
- )
-
- #: A :class:`~datetime.timedelta` or number of seconds which is used
- #: as the default ``max_age`` for :func:`send_file`. The default is
- #: ``None``, which tells the browser to use conditional requests
- #: instead of a timed cache.
- #:
- #: Configured with the :data:`SEND_FILE_MAX_AGE_DEFAULT`
- #: configuration key.
- #:
- #: .. versionchanged:: 2.0
- #: Defaults to ``None`` instead of 12 hours.
- send_file_max_age_default = ConfigAttribute(
- "SEND_FILE_MAX_AGE_DEFAULT", get_converter=_make_timedelta
- )
-
- #: Enable this if you want to use the X-Sendfile feature. Keep in
- #: mind that the server has to support this. This only affects files
- #: sent with the :func:`send_file` method.
- #:
- #: .. versionadded:: 0.2
- #:
- #: This attribute can also be configured from the config with the
- #: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
- use_x_sendfile = ConfigAttribute("USE_X_SENDFILE")
-
- #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`.
- #:
- #: .. versionadded:: 0.10
- json_encoder = json.JSONEncoder
-
- #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`.
- #:
- #: .. versionadded:: 0.10
- json_decoder = json.JSONDecoder
-
- #: Options that are passed to the Jinja environment in
- #: :meth:`create_jinja_environment`. Changing these options after
- #: the environment is created (accessing :attr:`jinja_env`) will
- #: have no effect.
- #:
- #: .. versionchanged:: 1.1.0
- #: This is a ``dict`` instead of an ``ImmutableDict`` to allow
- #: easier configuration.
- #:
- jinja_options: dict = {}
-
- #: Default configuration parameters.
- default_config = ImmutableDict(
- {
- "ENV": None,
- "DEBUG": None,
- "TESTING": False,
- "PROPAGATE_EXCEPTIONS": None,
- "PRESERVE_CONTEXT_ON_EXCEPTION": None,
- "SECRET_KEY": None,
- "PERMANENT_SESSION_LIFETIME": timedelta(days=31),
- "USE_X_SENDFILE": False,
- "SERVER_NAME": None,
- "APPLICATION_ROOT": "/",
- "SESSION_COOKIE_NAME": "session",
- "SESSION_COOKIE_DOMAIN": None,
- "SESSION_COOKIE_PATH": None,
- "SESSION_COOKIE_HTTPONLY": True,
- "SESSION_COOKIE_SECURE": False,
- "SESSION_COOKIE_SAMESITE": None,
- "SESSION_REFRESH_EACH_REQUEST": True,
- "MAX_CONTENT_LENGTH": None,
- "SEND_FILE_MAX_AGE_DEFAULT": None,
- "TRAP_BAD_REQUEST_ERRORS": None,
- "TRAP_HTTP_EXCEPTIONS": False,
- "EXPLAIN_TEMPLATE_LOADING": False,
- "PREFERRED_URL_SCHEME": "http",
- "JSON_AS_ASCII": True,
- "JSON_SORT_KEYS": True,
- "JSONIFY_PRETTYPRINT_REGULAR": False,
- "JSONIFY_MIMETYPE": "application/json",
- "TEMPLATES_AUTO_RELOAD": None,
- "MAX_COOKIE_SIZE": 4093,
- }
- )
-
- #: The rule object to use for URL rules created. This is used by
- #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`.
- #:
- #: .. versionadded:: 0.7
- url_rule_class = Rule
-
- #: The map object to use for storing the URL rules and routing
- #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`.
- #:
- #: .. versionadded:: 1.1.0
- url_map_class = Map
-
- #: the test client that is used with when `test_client` is used.
- #:
- #: .. versionadded:: 0.7
- test_client_class: t.Optional[t.Type["FlaskClient"]] = None
-
- #: The :class:`~click.testing.CliRunner` subclass, by default
- #: :class:`~flask.testing.FlaskCliRunner` that is used by
- #: :meth:`test_cli_runner`. Its ``__init__`` method should take a
- #: Flask app object as the first argument.
- #:
- #: .. versionadded:: 1.0
- test_cli_runner_class: t.Optional[t.Type["FlaskCliRunner"]] = None
-
- #: the session interface to use. By default an instance of
- #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
- #:
- #: .. versionadded:: 0.8
- session_interface = SecureCookieSessionInterface()
-
- def __init__(
- self,
- import_name: str,
- static_url_path: t.Optional[str] = None,
- static_folder: t.Optional[str] = "static",
- static_host: t.Optional[str] = None,
- host_matching: bool = False,
- subdomain_matching: bool = False,
- template_folder: t.Optional[str] = "templates",
- instance_path: t.Optional[str] = None,
- instance_relative_config: bool = False,
- root_path: t.Optional[str] = None,
- ):
- super().__init__(
- import_name=import_name,
- static_folder=static_folder,
- static_url_path=static_url_path,
- template_folder=template_folder,
- root_path=root_path,
- )
-
- if instance_path is None:
- instance_path = self.auto_find_instance_path()
- elif not os.path.isabs(instance_path):
- raise ValueError(
- "If an instance path is provided it must be absolute."
- " A relative path was given instead."
- )
-
- #: Holds the path to the instance folder.
- #:
- #: .. versionadded:: 0.8
- self.instance_path = instance_path
-
- #: The configuration dictionary as :class:`Config`. This behaves
- #: exactly like a regular dictionary but supports additional methods
- #: to load a config from files.
- self.config = self.make_config(instance_relative_config)
-
- #: A list of functions that are called when :meth:`url_for` raises a
- #: :exc:`~werkzeug.routing.BuildError`. Each function registered here
- #: is called with `error`, `endpoint` and `values`. If a function
- #: returns ``None`` or raises a :exc:`BuildError` the next function is
- #: tried.
- #:
- #: .. versionadded:: 0.9
- self.url_build_error_handlers: t.List[
- t.Callable[[Exception, str, dict], str]
- ] = []
-
- #: A list of functions that will be called at the beginning of the
- #: first request to this instance. To register a function, use the
- #: :meth:`before_first_request` decorator.
- #:
- #: .. versionadded:: 0.8
- self.before_first_request_funcs: t.List[BeforeRequestCallable] = []
-
- #: A list of functions that are called when the application context
- #: is destroyed. Since the application context is also torn down
- #: if the request ends this is the place to store code that disconnects
- #: from databases.
- #:
- #: .. versionadded:: 0.9
- self.teardown_appcontext_funcs: t.List[TeardownCallable] = []
-
- #: A list of shell context processor functions that should be run
- #: when a shell context is created.
- #:
- #: .. versionadded:: 0.11
- self.shell_context_processors: t.List[t.Callable[[], t.Dict[str, t.Any]]] = []
-
- #: Maps registered blueprint names to blueprint objects. The
- #: dict retains the order the blueprints were registered in.
- #: Blueprints can be registered multiple times, this dict does
- #: not track how often they were attached.
- #:
- #: .. versionadded:: 0.7
- self.blueprints: t.Dict[str, "Blueprint"] = {}
-
- #: a place where extensions can store application specific state. For
- #: example this is where an extension could store database engines and
- #: similar things.
- #:
- #: The key must match the name of the extension module. For example in
- #: case of a "Flask-Foo" extension in `flask_foo`, the key would be
- #: ``'foo'``.
- #:
- #: .. versionadded:: 0.7
- self.extensions: dict = {}
-
- #: The :class:`~werkzeug.routing.Map` for this instance. You can use
- #: this to change the routing converters after the class was created
- #: but before any routes are connected. Example::
- #:
- #: from werkzeug.routing import BaseConverter
- #:
- #: class ListConverter(BaseConverter):
- #: def to_python(self, value):
- #: return value.split(',')
- #: def to_url(self, values):
- #: return ','.join(super(ListConverter, self).to_url(value)
- #: for value in values)
- #:
- #: app = Flask(__name__)
- #: app.url_map.converters['list'] = ListConverter
- self.url_map = self.url_map_class()
-
- self.url_map.host_matching = host_matching
- self.subdomain_matching = subdomain_matching
-
- # tracks internally if the application already handled at least one
- # request.
- self._got_first_request = False
- self._before_request_lock = Lock()
-
- # Add a static route using the provided static_url_path, static_host,
- # and static_folder if there is a configured static_folder.
- # Note we do this without checking if static_folder exists.
- # For one, it might be created while the server is running (e.g. during
- # development). Also, Google App Engine stores static files somewhere
- if self.has_static_folder:
- assert (
- bool(static_host) == host_matching
- ), "Invalid static_host/host_matching combination"
- # Use a weakref to avoid creating a reference cycle between the app
- # and the view function (see #3761).
- self_ref = weakref.ref(self)
- self.add_url_rule(
- f"{self.static_url_path}/",
- endpoint="static",
- host=static_host,
- view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore # noqa: B950
- )
-
- # Set the name of the Click group in case someone wants to add
- # the app's commands to another CLI tool.
- self.cli.name = self.name
-
- def _is_setup_finished(self) -> bool:
- return self.debug and self._got_first_request
-
- @locked_cached_property
- def name(self) -> str: # type: ignore
- """The name of the application. This is usually the import name
- with the difference that it's guessed from the run file if the
- import name is main. This name is used as a display name when
- Flask needs the name of the application. It can be set and overridden
- to change the value.
-
- .. versionadded:: 0.8
- """
- if self.import_name == "__main__":
- fn = getattr(sys.modules["__main__"], "__file__", None)
- if fn is None:
- return "__main__"
- return os.path.splitext(os.path.basename(fn))[0]
- return self.import_name
-
- @property
- def propagate_exceptions(self) -> bool:
- """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
- value in case it's set, otherwise a sensible default is returned.
-
- .. versionadded:: 0.7
- """
- rv = self.config["PROPAGATE_EXCEPTIONS"]
- if rv is not None:
- return rv
- return self.testing or self.debug
-
- @property
- def preserve_context_on_exception(self) -> bool:
- """Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION``
- configuration value in case it's set, otherwise a sensible default
- is returned.
-
- .. versionadded:: 0.7
- """
- rv = self.config["PRESERVE_CONTEXT_ON_EXCEPTION"]
- if rv is not None:
- return rv
- return self.debug
-
- @locked_cached_property
- def logger(self) -> logging.Logger:
- """A standard Python :class:`~logging.Logger` for the app, with
- the same name as :attr:`name`.
-
- In debug mode, the logger's :attr:`~logging.Logger.level` will
- be set to :data:`~logging.DEBUG`.
-
- If there are no handlers configured, a default handler will be
- added. See :doc:`/logging` for more information.
-
- .. versionchanged:: 1.1.0
- The logger takes the same name as :attr:`name` rather than
- hard-coding ``"flask.app"``.
-
- .. versionchanged:: 1.0.0
- Behavior was simplified. The logger is always named
- ``"flask.app"``. The level is only set during configuration,
- it doesn't check ``app.debug`` each time. Only one format is
- used, not different ones depending on ``app.debug``. No
- handlers are removed, and a handler is only added if no
- handlers are already configured.
-
- .. versionadded:: 0.3
- """
- return create_logger(self)
-
- @locked_cached_property
- def jinja_env(self) -> Environment:
- """The Jinja environment used to load templates.
-
- The environment is created the first time this property is
- accessed. Changing :attr:`jinja_options` after that will have no
- effect.
- """
- return self.create_jinja_environment()
-
- @property
- def got_first_request(self) -> bool:
- """This attribute is set to ``True`` if the application started
- handling the first request.
-
- .. versionadded:: 0.8
- """
- return self._got_first_request
-
- def make_config(self, instance_relative: bool = False) -> Config:
- """Used to create the config attribute by the Flask constructor.
- The `instance_relative` parameter is passed in from the constructor
- of Flask (there named `instance_relative_config`) and indicates if
- the config should be relative to the instance path or the root path
- of the application.
-
- .. versionadded:: 0.8
- """
- root_path = self.root_path
- if instance_relative:
- root_path = self.instance_path
- defaults = dict(self.default_config)
- defaults["ENV"] = get_env()
- defaults["DEBUG"] = get_debug_flag()
- return self.config_class(root_path, defaults)
-
- def auto_find_instance_path(self) -> str:
- """Tries to locate the instance path if it was not provided to the
- constructor of the application class. It will basically calculate
- the path to a folder named ``instance`` next to your main file or
- the package.
-
- .. versionadded:: 0.8
- """
- prefix, package_path = find_package(self.import_name)
- if prefix is None:
- return os.path.join(package_path, "instance")
- return os.path.join(prefix, "var", f"{self.name}-instance")
-
- def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]:
- """Opens a resource from the application's instance folder
- (:attr:`instance_path`). Otherwise works like
- :meth:`open_resource`. Instance resources can also be opened for
- writing.
-
- :param resource: the name of the resource. To access resources within
- subfolders use forward slashes as separator.
- :param mode: resource file opening mode, default is 'rb'.
- """
- return open(os.path.join(self.instance_path, resource), mode)
-
- @property
- def templates_auto_reload(self) -> bool:
- """Reload templates when they are changed. Used by
- :meth:`create_jinja_environment`.
-
- This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If
- not set, it will be enabled in debug mode.
-
- .. versionadded:: 1.0
- This property was added but the underlying config and behavior
- already existed.
- """
- rv = self.config["TEMPLATES_AUTO_RELOAD"]
- return rv if rv is not None else self.debug
-
- @templates_auto_reload.setter
- def templates_auto_reload(self, value: bool) -> None:
- self.config["TEMPLATES_AUTO_RELOAD"] = value
-
- def create_jinja_environment(self) -> Environment:
- """Create the Jinja environment based on :attr:`jinja_options`
- and the various Jinja-related methods of the app. Changing
- :attr:`jinja_options` after this will have no effect. Also adds
- Flask-related globals and filters to the environment.
-
- .. versionchanged:: 0.11
- ``Environment.auto_reload`` set in accordance with
- ``TEMPLATES_AUTO_RELOAD`` configuration option.
-
- .. versionadded:: 0.5
- """
- options = dict(self.jinja_options)
-
- if "autoescape" not in options:
- options["autoescape"] = self.select_jinja_autoescape
-
- if "auto_reload" not in options:
- options["auto_reload"] = self.templates_auto_reload
-
- rv = self.jinja_environment(self, **options)
- rv.globals.update(
- url_for=url_for,
- get_flashed_messages=get_flashed_messages,
- config=self.config,
- # request, session and g are normally added with the
- # context processor for efficiency reasons but for imported
- # templates we also want the proxies in there.
- request=request,
- session=session,
- g=g,
- )
- rv.policies["json.dumps_function"] = json.dumps
- return rv
-
- def create_global_jinja_loader(self) -> DispatchingJinjaLoader:
- """Creates the loader for the Jinja2 environment. Can be used to
- override just the loader and keeping the rest unchanged. It's
- discouraged to override this function. Instead one should override
- the :meth:`jinja_loader` function instead.
-
- The global loader dispatches between the loaders of the application
- and the individual blueprints.
-
- .. versionadded:: 0.7
- """
- return DispatchingJinjaLoader(self)
-
- def select_jinja_autoescape(self, filename: str) -> bool:
- """Returns ``True`` if autoescaping should be active for the given
- template name. If no template name is given, returns `True`.
-
- .. versionadded:: 0.5
- """
- if filename is None:
- return True
- return filename.endswith((".html", ".htm", ".xml", ".xhtml"))
-
- def update_template_context(self, context: dict) -> None:
- """Update the template context with some commonly used variables.
- This injects request, session, config and g into the template
- context as well as everything template context processors want
- to inject. Note that the as of Flask 0.6, the original values
- in the context will not be overridden if a context processor
- decides to return a value with the same key.
-
- :param context: the context as a dictionary that is updated in place
- to add extra variables.
- """
- funcs: t.Iterable[
- TemplateContextProcessorCallable
- ] = self.template_context_processors[None]
- reqctx = _request_ctx_stack.top
- if reqctx is not None:
- for bp in request.blueprints:
- if bp in self.template_context_processors:
- funcs = chain(funcs, self.template_context_processors[bp])
- orig_ctx = context.copy()
- for func in funcs:
- context.update(func())
- # make sure the original values win. This makes it possible to
- # easier add new variables in context processors without breaking
- # existing views.
- context.update(orig_ctx)
-
- def make_shell_context(self) -> dict:
- """Returns the shell context for an interactive shell for this
- application. This runs all the registered shell context
- processors.
-
- .. versionadded:: 0.11
- """
- rv = {"app": self, "g": g}
- for processor in self.shell_context_processors:
- rv.update(processor())
- return rv
-
- #: What environment the app is running in. Flask and extensions may
- #: enable behaviors based on the environment, such as enabling debug
- #: mode. This maps to the :data:`ENV` config key. This is set by the
- #: :envvar:`FLASK_ENV` environment variable and may not behave as
- #: expected if set in code.
- #:
- #: **Do not enable development when deploying in production.**
- #:
- #: Default: ``'production'``
- env = ConfigAttribute("ENV")
-
- @property
- def debug(self) -> bool:
- """Whether debug mode is enabled. When using ``flask run`` to start
- the development server, an interactive debugger will be shown for
- unhandled exceptions, and the server will be reloaded when code
- changes. This maps to the :data:`DEBUG` config key. This is
- enabled when :attr:`env` is ``'development'`` and is overridden
- by the ``FLASK_DEBUG`` environment variable. It may not behave as
- expected if set in code.
-
- **Do not enable debug mode when deploying in production.**
-
- Default: ``True`` if :attr:`env` is ``'development'``, or
- ``False`` otherwise.
- """
- return self.config["DEBUG"]
-
- @debug.setter
- def debug(self, value: bool) -> None:
- self.config["DEBUG"] = value
- self.jinja_env.auto_reload = self.templates_auto_reload
-
- def run(
- self,
- host: t.Optional[str] = None,
- port: t.Optional[int] = None,
- debug: t.Optional[bool] = None,
- load_dotenv: bool = True,
- **options: t.Any,
- ) -> None:
- """Runs the application on a local development server.
-
- Do not use ``run()`` in a production setting. It is not intended to
- meet security and performance requirements for a production server.
- Instead, see :doc:`/deploying/index` for WSGI server recommendations.
-
- If the :attr:`debug` flag is set the server will automatically reload
- for code changes and show a debugger in case an exception happened.
-
- If you want to run the application in debug mode, but disable the
- code execution on the interactive debugger, you can pass
- ``use_evalex=False`` as parameter. This will keep the debugger's
- traceback screen active, but disable code execution.
-
- It is not recommended to use this function for development with
- automatic reloading as this is badly supported. Instead you should
- be using the :command:`flask` command line script's ``run`` support.
-
- .. admonition:: Keep in Mind
-
- Flask will suppress any server error with a generic error page
- unless it is in debug mode. As such to enable just the
- interactive debugger without the code reloading, you have to
- invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.
- Setting ``use_debugger`` to ``True`` without being in debug mode
- won't catch any exceptions because there won't be any to
- catch.
-
- :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to
- have the server available externally as well. Defaults to
- ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable
- if present.
- :param port: the port of the webserver. Defaults to ``5000`` or the
- port defined in the ``SERVER_NAME`` config variable if present.
- :param debug: if given, enable or disable debug mode. See
- :attr:`debug`.
- :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
- files to set environment variables. Will also change the working
- directory to the directory containing the first file found.
- :param options: the options to be forwarded to the underlying Werkzeug
- server. See :func:`werkzeug.serving.run_simple` for more
- information.
-
- .. versionchanged:: 1.0
- If installed, python-dotenv will be used to load environment
- variables from :file:`.env` and :file:`.flaskenv` files.
-
- If set, the :envvar:`FLASK_ENV` and :envvar:`FLASK_DEBUG`
- environment variables will override :attr:`env` and
- :attr:`debug`.
-
- Threaded mode is enabled by default.
-
- .. versionchanged:: 0.10
- The default port is now picked from the ``SERVER_NAME``
- variable.
- """
- # Change this into a no-op if the server is invoked from the
- # command line. Have a look at cli.py for more information.
- if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
- from .debughelpers import explain_ignored_app_run
-
- explain_ignored_app_run()
- return
-
- if get_load_dotenv(load_dotenv):
- cli.load_dotenv()
-
- # if set, let env vars override previous values
- if "FLASK_ENV" in os.environ:
- self.env = get_env()
- self.debug = get_debug_flag()
- elif "FLASK_DEBUG" in os.environ:
- self.debug = get_debug_flag()
-
- # debug passed to method overrides all other sources
- if debug is not None:
- self.debug = bool(debug)
-
- server_name = self.config.get("SERVER_NAME")
- sn_host = sn_port = None
-
- if server_name:
- sn_host, _, sn_port = server_name.partition(":")
-
- if not host:
- if sn_host:
- host = sn_host
- else:
- host = "127.0.0.1"
-
- if port or port == 0:
- port = int(port)
- elif sn_port:
- port = int(sn_port)
- else:
- port = 5000
-
- options.setdefault("use_reloader", self.debug)
- options.setdefault("use_debugger", self.debug)
- options.setdefault("threaded", True)
-
- cli.show_server_banner(self.env, self.debug, self.name, False)
-
- from werkzeug.serving import run_simple
-
- try:
- run_simple(t.cast(str, host), port, self, **options)
- finally:
- # reset the first request information if the development server
- # reset normally. This makes it possible to restart the server
- # without reloader and that stuff from an interactive shell.
- self._got_first_request = False
-
- def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> "FlaskClient":
- """Creates a test client for this application. For information
- about unit testing head over to :doc:`/testing`.
-
- Note that if you are testing for assertions or exceptions in your
- application code, you must set ``app.testing = True`` in order for the
- exceptions to propagate to the test client. Otherwise, the exception
- will be handled by the application (not visible to the test client) and
- the only indication of an AssertionError or other exception will be a
- 500 status code response to the test client. See the :attr:`testing`
- attribute. For example::
-
- app.testing = True
- client = app.test_client()
-
- The test client can be used in a ``with`` block to defer the closing down
- of the context until the end of the ``with`` block. This is useful if
- you want to access the context locals for testing::
-
- with app.test_client() as c:
- rv = c.get('/?vodka=42')
- assert request.args['vodka'] == '42'
-
- Additionally, you may pass optional keyword arguments that will then
- be passed to the application's :attr:`test_client_class` constructor.
- For example::
-
- from flask.testing import FlaskClient
-
- class CustomClient(FlaskClient):
- def __init__(self, *args, **kwargs):
- self._authentication = kwargs.pop("authentication")
- super(CustomClient,self).__init__( *args, **kwargs)
-
- app.test_client_class = CustomClient
- client = app.test_client(authentication='Basic ....')
-
- See :class:`~flask.testing.FlaskClient` for more information.
-
- .. versionchanged:: 0.4
- added support for ``with`` block usage for the client.
-
- .. versionadded:: 0.7
- The `use_cookies` parameter was added as well as the ability
- to override the client to be used by setting the
- :attr:`test_client_class` attribute.
-
- .. versionchanged:: 0.11
- Added `**kwargs` to support passing additional keyword arguments to
- the constructor of :attr:`test_client_class`.
- """
- cls = self.test_client_class
- if cls is None:
- from .testing import FlaskClient as cls # type: ignore
- return cls( # type: ignore
- self, self.response_class, use_cookies=use_cookies, **kwargs
- )
-
- def test_cli_runner(self, **kwargs: t.Any) -> "FlaskCliRunner":
- """Create a CLI runner for testing CLI commands.
- See :ref:`testing-cli`.
-
- Returns an instance of :attr:`test_cli_runner_class`, by default
- :class:`~flask.testing.FlaskCliRunner`. The Flask app object is
- passed as the first argument.
-
- .. versionadded:: 1.0
- """
- cls = self.test_cli_runner_class
-
- if cls is None:
- from .testing import FlaskCliRunner as cls # type: ignore
-
- return cls(self, **kwargs) # type: ignore
-
- @setupmethod
- def register_blueprint(self, blueprint: "Blueprint", **options: t.Any) -> None:
- """Register a :class:`~flask.Blueprint` on the application. Keyword
- arguments passed to this method will override the defaults set on the
- blueprint.
-
- Calls the blueprint's :meth:`~flask.Blueprint.register` method after
- recording the blueprint in the application's :attr:`blueprints`.
-
- :param blueprint: The blueprint to register.
- :param url_prefix: Blueprint routes will be prefixed with this.
- :param subdomain: Blueprint routes will match on this subdomain.
- :param url_defaults: Blueprint routes will use these default values for
- view arguments.
- :param options: Additional keyword arguments are passed to
- :class:`~flask.blueprints.BlueprintSetupState`. They can be
- accessed in :meth:`~flask.Blueprint.record` callbacks.
-
- .. versionchanged:: 2.0.1
- The ``name`` option can be used to change the (pre-dotted)
- name the blueprint is registered with. This allows the same
- blueprint to be registered multiple times with unique names
- for ``url_for``.
-
- .. versionadded:: 0.7
- """
- blueprint.register(self, options)
-
- def iter_blueprints(self) -> t.ValuesView["Blueprint"]:
- """Iterates over all blueprints by the order they were registered.
-
- .. versionadded:: 0.11
- """
- return self.blueprints.values()
-
- @setupmethod
- def add_url_rule(
- self,
- rule: str,
- endpoint: t.Optional[str] = None,
- view_func: t.Optional[t.Callable] = None,
- provide_automatic_options: t.Optional[bool] = None,
- **options: t.Any,
- ) -> None:
- if endpoint is None:
- endpoint = _endpoint_from_view_func(view_func) # type: ignore
- options["endpoint"] = endpoint
- methods = options.pop("methods", None)
-
- # if the methods are not given and the view_func object knows its
- # methods we can use that instead. If neither exists, we go with
- # a tuple of only ``GET`` as default.
- if methods is None:
- methods = getattr(view_func, "methods", None) or ("GET",)
- if isinstance(methods, str):
- raise TypeError(
- "Allowed methods must be a list of strings, for"
- ' example: @app.route(..., methods=["POST"])'
- )
- methods = {item.upper() for item in methods}
-
- # Methods that should always be added
- required_methods = set(getattr(view_func, "required_methods", ()))
-
- # starting with Flask 0.8 the view_func object can disable and
- # force-enable the automatic options handling.
- if provide_automatic_options is None:
- provide_automatic_options = getattr(
- view_func, "provide_automatic_options", None
- )
-
- if provide_automatic_options is None:
- if "OPTIONS" not in methods:
- provide_automatic_options = True
- required_methods.add("OPTIONS")
- else:
- provide_automatic_options = False
-
- # Add the required methods now.
- methods |= required_methods
-
- rule = self.url_rule_class(rule, methods=methods, **options)
- rule.provide_automatic_options = provide_automatic_options # type: ignore
-
- self.url_map.add(rule)
- if view_func is not None:
- old_func = self.view_functions.get(endpoint)
- if old_func is not None and old_func != view_func:
- raise AssertionError(
- "View function mapping is overwriting an existing"
- f" endpoint function: {endpoint}"
- )
- self.view_functions[endpoint] = view_func
-
- @setupmethod
- def template_filter(
- self, name: t.Optional[str] = None
- ) -> t.Callable[[TemplateFilterCallable], TemplateFilterCallable]:
- """A decorator that is used to register custom template filter.
- You can specify a name for the filter, otherwise the function
- name will be used. Example::
-
- @app.template_filter()
- def reverse(s):
- return s[::-1]
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
-
- def decorator(f: TemplateFilterCallable) -> TemplateFilterCallable:
- self.add_template_filter(f, name=name)
- return f
-
- return decorator
-
- @setupmethod
- def add_template_filter(
- self, f: TemplateFilterCallable, name: t.Optional[str] = None
- ) -> None:
- """Register a custom template filter. Works exactly like the
- :meth:`template_filter` decorator.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- self.jinja_env.filters[name or f.__name__] = f
-
- @setupmethod
- def template_test(
- self, name: t.Optional[str] = None
- ) -> t.Callable[[TemplateTestCallable], TemplateTestCallable]:
- """A decorator that is used to register custom template test.
- You can specify a name for the test, otherwise the function
- name will be used. Example::
-
- @app.template_test()
- def is_prime(n):
- if n == 2:
- return True
- for i in range(2, int(math.ceil(math.sqrt(n))) + 1):
- if n % i == 0:
- return False
- return True
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
-
- def decorator(f: TemplateTestCallable) -> TemplateTestCallable:
- self.add_template_test(f, name=name)
- return f
-
- return decorator
-
- @setupmethod
- def add_template_test(
- self, f: TemplateTestCallable, name: t.Optional[str] = None
- ) -> None:
- """Register a custom template test. Works exactly like the
- :meth:`template_test` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- self.jinja_env.tests[name or f.__name__] = f
-
- @setupmethod
- def template_global(
- self, name: t.Optional[str] = None
- ) -> t.Callable[[TemplateGlobalCallable], TemplateGlobalCallable]:
- """A decorator that is used to register a custom template global function.
- You can specify a name for the global function, otherwise the function
- name will be used. Example::
-
- @app.template_global()
- def double(n):
- return 2 * n
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
-
- def decorator(f: TemplateGlobalCallable) -> TemplateGlobalCallable:
- self.add_template_global(f, name=name)
- return f
-
- return decorator
-
- @setupmethod
- def add_template_global(
- self, f: TemplateGlobalCallable, name: t.Optional[str] = None
- ) -> None:
- """Register a custom template global function. Works exactly like the
- :meth:`template_global` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
- self.jinja_env.globals[name or f.__name__] = f
-
- @setupmethod
- def before_first_request(self, f: BeforeRequestCallable) -> BeforeRequestCallable:
- """Registers a function to be run before the first request to this
- instance of the application.
-
- The function will be called without any arguments and its return
- value is ignored.
-
- .. versionadded:: 0.8
- """
- self.before_first_request_funcs.append(f)
- return f
-
- @setupmethod
- def teardown_appcontext(self, f: TeardownCallable) -> TeardownCallable:
- """Registers a function to be called when the application context
- ends. These functions are typically also called when the request
- context is popped.
-
- Example::
-
- ctx = app.app_context()
- ctx.push()
- ...
- ctx.pop()
-
- When ``ctx.pop()`` is executed in the above example, the teardown
- functions are called just before the app context moves from the
- stack of active contexts. This becomes relevant if you are using
- such constructs in tests.
-
- Since a request context typically also manages an application
- context it would also be called when you pop a request context.
-
- When a teardown function was called because of an unhandled exception
- it will be passed an error object. If an :meth:`errorhandler` is
- registered, it will handle the exception and the teardown will not
- receive it.
-
- The return values of teardown functions are ignored.
-
- .. versionadded:: 0.9
- """
- self.teardown_appcontext_funcs.append(f)
- return f
-
- @setupmethod
- def shell_context_processor(self, f: t.Callable) -> t.Callable:
- """Registers a shell context processor function.
-
- .. versionadded:: 0.11
- """
- self.shell_context_processors.append(f)
- return f
-
- def _find_error_handler(self, e: Exception) -> t.Optional[ErrorHandlerCallable]:
- """Return a registered error handler for an exception in this order:
- blueprint handler for a specific code, app handler for a specific code,
- blueprint handler for an exception class, app handler for an exception
- class, or ``None`` if a suitable handler is not found.
- """
- exc_class, code = self._get_exc_class_and_code(type(e))
-
- for c in [code, None]:
- for name in chain(request.blueprints, [None]):
- handler_map = self.error_handler_spec[name][c]
-
- if not handler_map:
- continue
-
- for cls in exc_class.__mro__:
- handler = handler_map.get(cls)
-
- if handler is not None:
- return handler
- return None
-
- def handle_http_exception(
- self, e: HTTPException
- ) -> t.Union[HTTPException, ResponseReturnValue]:
- """Handles an HTTP exception. By default this will invoke the
- registered error handlers and fall back to returning the
- exception as response.
-
- .. versionchanged:: 1.0.3
- ``RoutingException``, used internally for actions such as
- slash redirects during routing, is not passed to error
- handlers.
-
- .. versionchanged:: 1.0
- Exceptions are looked up by code *and* by MRO, so
- ``HTTPExcpetion`` subclasses can be handled with a catch-all
- handler for the base ``HTTPException``.
-
- .. versionadded:: 0.3
- """
- # Proxy exceptions don't have error codes. We want to always return
- # those unchanged as errors
- if e.code is None:
- return e
-
- # RoutingExceptions are used internally to trigger routing
- # actions, such as slash redirects raising RequestRedirect. They
- # are not raised or handled in user code.
- if isinstance(e, RoutingException):
- return e
-
- handler = self._find_error_handler(e)
- if handler is None:
- return e
- return self.ensure_sync(handler)(e)
-
- def trap_http_exception(self, e: Exception) -> bool:
- """Checks if an HTTP exception should be trapped or not. By default
- this will return ``False`` for all exceptions except for a bad request
- key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It
- also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``.
-
- This is called for all HTTP exceptions raised by a view function.
- If it returns ``True`` for any exception the error handler for this
- exception is not called and it shows up as regular exception in the
- traceback. This is helpful for debugging implicitly raised HTTP
- exceptions.
-
- .. versionchanged:: 1.0
- Bad request errors are not trapped by default in debug mode.
-
- .. versionadded:: 0.8
- """
- if self.config["TRAP_HTTP_EXCEPTIONS"]:
- return True
-
- trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"]
-
- # if unset, trap key errors in debug mode
- if (
- trap_bad_request is None
- and self.debug
- and isinstance(e, BadRequestKeyError)
- ):
- return True
-
- if trap_bad_request:
- return isinstance(e, BadRequest)
-
- return False
-
- def handle_user_exception(
- self, e: Exception
- ) -> t.Union[HTTPException, ResponseReturnValue]:
- """This method is called whenever an exception occurs that
- should be handled. A special case is :class:`~werkzeug
- .exceptions.HTTPException` which is forwarded to the
- :meth:`handle_http_exception` method. This function will either
- return a response value or reraise the exception with the same
- traceback.
-
- .. versionchanged:: 1.0
- Key errors raised from request data like ``form`` show the
- bad key in debug mode rather than a generic bad request
- message.
-
- .. versionadded:: 0.7
- """
- if isinstance(e, BadRequestKeyError) and (
- self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]
- ):
- e.show_exception = True
-
- if isinstance(e, HTTPException) and not self.trap_http_exception(e):
- return self.handle_http_exception(e)
-
- handler = self._find_error_handler(e)
-
- if handler is None:
- raise
-
- return self.ensure_sync(handler)(e)
-
- def handle_exception(self, e: Exception) -> Response:
- """Handle an exception that did not have an error handler
- associated with it, or that was raised from an error handler.
- This always causes a 500 ``InternalServerError``.
-
- Always sends the :data:`got_request_exception` signal.
-
- If :attr:`propagate_exceptions` is ``True``, such as in debug
- mode, the error will be re-raised so that the debugger can
- display it. Otherwise, the original exception is logged, and
- an :exc:`~werkzeug.exceptions.InternalServerError` is returned.
-
- If an error handler is registered for ``InternalServerError`` or
- ``500``, it will be used. For consistency, the handler will
- always receive the ``InternalServerError``. The original
- unhandled exception is available as ``e.original_exception``.
-
- .. versionchanged:: 1.1.0
- Always passes the ``InternalServerError`` instance to the
- handler, setting ``original_exception`` to the unhandled
- error.
-
- .. versionchanged:: 1.1.0
- ``after_request`` functions and other finalization is done
- even for the default 500 response when there is no handler.
-
- .. versionadded:: 0.3
- """
- exc_info = sys.exc_info()
- got_request_exception.send(self, exception=e)
-
- if self.propagate_exceptions:
- # Re-raise if called with an active exception, otherwise
- # raise the passed in exception.
- if exc_info[1] is e:
- raise
-
- raise e
-
- self.log_exception(exc_info)
- server_error: t.Union[InternalServerError, ResponseReturnValue]
- server_error = InternalServerError(original_exception=e)
- handler = self._find_error_handler(server_error)
-
- if handler is not None:
- server_error = self.ensure_sync(handler)(server_error)
-
- return self.finalize_request(server_error, from_error_handler=True)
-
- def log_exception(
- self,
- exc_info: t.Union[
- t.Tuple[type, BaseException, TracebackType], t.Tuple[None, None, None]
- ],
- ) -> None:
- """Logs an exception. This is called by :meth:`handle_exception`
- if debugging is disabled and right before the handler is called.
- The default implementation logs the exception as error on the
- :attr:`logger`.
-
- .. versionadded:: 0.8
- """
- self.logger.error(
- f"Exception on {request.path} [{request.method}]", exc_info=exc_info
- )
-
- def raise_routing_exception(self, request: Request) -> "te.NoReturn":
- """Exceptions that are recording during routing are reraised with
- this method. During debug we are not reraising redirect requests
- for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising
- a different error instead to help debug situations.
-
- :internal:
- """
- if (
- not self.debug
- or not isinstance(request.routing_exception, RequestRedirect)
- or request.method in ("GET", "HEAD", "OPTIONS")
- ):
- raise request.routing_exception # type: ignore
-
- from .debughelpers import FormDataRoutingRedirect
-
- raise FormDataRoutingRedirect(request)
-
- def dispatch_request(self) -> ResponseReturnValue:
- """Does the request dispatching. Matches the URL and returns the
- return value of the view or error handler. This does not have to
- be a response object. In order to convert the return value to a
- proper response object, call :func:`make_response`.
-
- .. versionchanged:: 0.7
- This no longer does the exception handling, this code was
- moved to the new :meth:`full_dispatch_request`.
- """
- req = _request_ctx_stack.top.request
- if req.routing_exception is not None:
- self.raise_routing_exception(req)
- rule = req.url_rule
- # if we provide automatic options for this URL and the
- # request came with the OPTIONS method, reply automatically
- if (
- getattr(rule, "provide_automatic_options", False)
- and req.method == "OPTIONS"
- ):
- return self.make_default_options_response()
- # otherwise dispatch to the handler for that endpoint
- return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
-
- def full_dispatch_request(self) -> Response:
- """Dispatches the request and on top of that performs request
- pre and postprocessing as well as HTTP exception catching and
- error handling.
-
- .. versionadded:: 0.7
- """
- self.try_trigger_before_first_request_functions()
- try:
- request_started.send(self)
- rv = self.preprocess_request()
- if rv is None:
- rv = self.dispatch_request()
- except Exception as e:
- rv = self.handle_user_exception(e)
- return self.finalize_request(rv)
-
- def finalize_request(
- self,
- rv: t.Union[ResponseReturnValue, HTTPException],
- from_error_handler: bool = False,
- ) -> Response:
- """Given the return value from a view function this finalizes
- the request by converting it into a response and invoking the
- postprocessing functions. This is invoked for both normal
- request dispatching as well as error handlers.
-
- Because this means that it might be called as a result of a
- failure a special safe mode is available which can be enabled
- with the `from_error_handler` flag. If enabled, failures in
- response processing will be logged and otherwise ignored.
-
- :internal:
- """
- response = self.make_response(rv)
- try:
- response = self.process_response(response)
- request_finished.send(self, response=response)
- except Exception:
- if not from_error_handler:
- raise
- self.logger.exception(
- "Request finalizing failed with an error while handling an error"
- )
- return response
-
- def try_trigger_before_first_request_functions(self) -> None:
- """Called before each request and will ensure that it triggers
- the :attr:`before_first_request_funcs` and only exactly once per
- application instance (which means process usually).
-
- :internal:
- """
- if self._got_first_request:
- return
- with self._before_request_lock:
- if self._got_first_request:
- return
- for func in self.before_first_request_funcs:
- self.ensure_sync(func)()
- self._got_first_request = True
-
- def make_default_options_response(self) -> Response:
- """This method is called to create the default ``OPTIONS`` response.
- This can be changed through subclassing to change the default
- behavior of ``OPTIONS`` responses.
-
- .. versionadded:: 0.7
- """
- adapter = _request_ctx_stack.top.url_adapter
- methods = adapter.allowed_methods()
- rv = self.response_class()
- rv.allow.update(methods)
- return rv
-
- def should_ignore_error(self, error: t.Optional[BaseException]) -> bool:
- """This is called to figure out if an error should be ignored
- or not as far as the teardown system is concerned. If this
- function returns ``True`` then the teardown handlers will not be
- passed the error.
-
- .. versionadded:: 0.10
- """
- return False
-
- def ensure_sync(self, func: t.Callable) -> t.Callable:
- """Ensure that the function is synchronous for WSGI workers.
- Plain ``def`` functions are returned as-is. ``async def``
- functions are wrapped to run and wait for the response.
-
- Override this method to change how the app runs async views.
-
- .. versionadded:: 2.0
- """
- if iscoroutinefunction(func):
- return self.async_to_sync(func)
-
- return func
-
- def async_to_sync(
- self, func: t.Callable[..., t.Coroutine]
- ) -> t.Callable[..., t.Any]:
- """Return a sync function that will run the coroutine function.
-
- .. code-block:: python
-
- result = app.async_to_sync(func)(*args, **kwargs)
-
- Override this method to change how the app converts async code
- to be synchronously callable.
-
- .. versionadded:: 2.0
- """
- try:
- from asgiref.sync import async_to_sync as asgiref_async_to_sync
- except ImportError:
- raise RuntimeError(
- "Install Flask with the 'async' extra in order to use async views."
- )
-
- # Check that Werkzeug isn't using its fallback ContextVar class.
- if ContextVar.__module__ == "werkzeug.local":
- raise RuntimeError(
- "Async cannot be used with this combination of Python "
- "and Greenlet versions."
- )
-
- return asgiref_async_to_sync(func)
-
- def make_response(self, rv: ResponseReturnValue) -> Response:
- """Convert the return value from a view function to an instance of
- :attr:`response_class`.
-
- :param rv: the return value from the view function. The view function
- must return a response. Returning ``None``, or the view ending
- without returning, is not allowed. The following types are allowed
- for ``view_rv``:
-
- ``str``
- A response object is created with the string encoded to UTF-8
- as the body.
-
- ``bytes``
- A response object is created with the bytes as the body.
-
- ``dict``
- A dictionary that will be jsonify'd before being returned.
-
- ``tuple``
- Either ``(body, status, headers)``, ``(body, status)``, or
- ``(body, headers)``, where ``body`` is any of the other types
- allowed here, ``status`` is a string or an integer, and
- ``headers`` is a dictionary or a list of ``(key, value)``
- tuples. If ``body`` is a :attr:`response_class` instance,
- ``status`` overwrites the exiting value and ``headers`` are
- extended.
-
- :attr:`response_class`
- The object is returned unchanged.
-
- other :class:`~werkzeug.wrappers.Response` class
- The object is coerced to :attr:`response_class`.
-
- :func:`callable`
- The function is called as a WSGI application. The result is
- used to create a response object.
-
- .. versionchanged:: 0.9
- Previously a tuple was interpreted as the arguments for the
- response object.
- """
-
- status = headers = None
-
- # unpack tuple returns
- if isinstance(rv, tuple):
- len_rv = len(rv)
-
- # a 3-tuple is unpacked directly
- if len_rv == 3:
- rv, status, headers = rv
- # decide if a 2-tuple has status or headers
- elif len_rv == 2:
- if isinstance(rv[1], (Headers, dict, tuple, list)):
- rv, headers = rv
- else:
- rv, status = rv
- # other sized tuples are not allowed
- else:
- raise TypeError(
- "The view function did not return a valid response tuple."
- " The tuple must have the form (body, status, headers),"
- " (body, status), or (body, headers)."
- )
-
- # the body must not be None
- if rv is None:
- raise TypeError(
- f"The view function for {request.endpoint!r} did not"
- " return a valid response. The function either returned"
- " None or ended without a return statement."
- )
-
- # make sure the body is an instance of the response class
- if not isinstance(rv, self.response_class):
- if isinstance(rv, (str, bytes, bytearray)):
- # let the response class set the status and headers instead of
- # waiting to do it manually, so that the class can handle any
- # special logic
- rv = self.response_class(rv, status=status, headers=headers)
- status = headers = None
- elif isinstance(rv, dict):
- rv = jsonify(rv)
- elif isinstance(rv, BaseResponse) or callable(rv):
- # evaluate a WSGI callable, or coerce a different response
- # class to the correct type
- try:
- rv = self.response_class.force_type(rv, request.environ) # type: ignore # noqa: B950
- except TypeError as e:
- raise TypeError(
- f"{e}\nThe view function did not return a valid"
- " response. The return type must be a string,"
- " dict, tuple, Response instance, or WSGI"
- f" callable, but it was a {type(rv).__name__}."
- ).with_traceback(sys.exc_info()[2])
- else:
- raise TypeError(
- "The view function did not return a valid"
- " response. The return type must be a string,"
- " dict, tuple, Response instance, or WSGI"
- f" callable, but it was a {type(rv).__name__}."
- )
-
- rv = t.cast(Response, rv)
- # prefer the status if it was provided
- if status is not None:
- if isinstance(status, (str, bytes, bytearray)):
- rv.status = status # type: ignore
- else:
- rv.status_code = status
-
- # extend existing headers with provided headers
- if headers:
- rv.headers.update(headers)
-
- return rv
-
- def create_url_adapter(
- self, request: t.Optional[Request]
- ) -> t.Optional[MapAdapter]:
- """Creates a URL adapter for the given request. The URL adapter
- is created at a point where the request context is not yet set
- up so the request is passed explicitly.
-
- .. versionadded:: 0.6
-
- .. versionchanged:: 0.9
- This can now also be called without a request object when the
- URL adapter is created for the application context.
-
- .. versionchanged:: 1.0
- :data:`SERVER_NAME` no longer implicitly enables subdomain
- matching. Use :attr:`subdomain_matching` instead.
- """
- if request is not None:
- # If subdomain matching is disabled (the default), use the
- # default subdomain in all cases. This should be the default
- # in Werkzeug but it currently does not have that feature.
- if not self.subdomain_matching:
- subdomain = self.url_map.default_subdomain or None
- else:
- subdomain = None
-
- return self.url_map.bind_to_environ(
- request.environ,
- server_name=self.config["SERVER_NAME"],
- subdomain=subdomain,
- )
- # We need at the very least the server name to be set for this
- # to work.
- if self.config["SERVER_NAME"] is not None:
- return self.url_map.bind(
- self.config["SERVER_NAME"],
- script_name=self.config["APPLICATION_ROOT"],
- url_scheme=self.config["PREFERRED_URL_SCHEME"],
- )
-
- return None
-
- def inject_url_defaults(self, endpoint: str, values: dict) -> None:
- """Injects the URL defaults for the given endpoint directly into
- the values dictionary passed. This is used internally and
- automatically called on URL building.
-
- .. versionadded:: 0.7
- """
- funcs: t.Iterable[URLDefaultCallable] = self.url_default_functions[None]
-
- if "." in endpoint:
- # This is called by url_for, which can be called outside a
- # request, can't use request.blueprints.
- bps = _split_blueprint_path(endpoint.rpartition(".")[0])
- bp_funcs = chain.from_iterable(self.url_default_functions[bp] for bp in bps)
- funcs = chain(funcs, bp_funcs)
-
- for func in funcs:
- func(endpoint, values)
-
- def handle_url_build_error(
- self, error: Exception, endpoint: str, values: dict
- ) -> str:
- """Handle :class:`~werkzeug.routing.BuildError` on
- :meth:`url_for`.
- """
- for handler in self.url_build_error_handlers:
- try:
- rv = handler(error, endpoint, values)
- except BuildError as e:
- # make error available outside except block
- error = e
- else:
- if rv is not None:
- return rv
-
- # Re-raise if called with an active exception, otherwise raise
- # the passed in exception.
- if error is sys.exc_info()[1]:
- raise
-
- raise error
-
- def preprocess_request(self) -> t.Optional[ResponseReturnValue]:
- """Called before the request is dispatched. Calls
- :attr:`url_value_preprocessors` registered with the app and the
- current blueprint (if any). Then calls :attr:`before_request_funcs`
- registered with the app and the blueprint.
-
- If any :meth:`before_request` handler returns a non-None value, the
- value is handled as if it was the return value from the view, and
- further request handling is stopped.
- """
-
- funcs: t.Iterable[URLValuePreprocessorCallable] = self.url_value_preprocessors[
- None
- ]
- for bp in request.blueprints:
- if bp in self.url_value_preprocessors:
- funcs = chain(funcs, self.url_value_preprocessors[bp])
- for func in funcs:
- func(request.endpoint, request.view_args)
-
- funcs: t.Iterable[BeforeRequestCallable] = self.before_request_funcs[None]
- for bp in request.blueprints:
- if bp in self.before_request_funcs:
- funcs = chain(funcs, self.before_request_funcs[bp])
- for func in funcs:
- rv = self.ensure_sync(func)()
- if rv is not None:
- return rv
-
- return None
-
- def process_response(self, response: Response) -> Response:
- """Can be overridden in order to modify the response object
- before it's sent to the WSGI server. By default this will
- call all the :meth:`after_request` decorated functions.
-
- .. versionchanged:: 0.5
- As of Flask 0.5 the functions registered for after request
- execution are called in reverse order of registration.
-
- :param response: a :attr:`response_class` object.
- :return: a new response object or the same, has to be an
- instance of :attr:`response_class`.
- """
- ctx = _request_ctx_stack.top
- funcs: t.Iterable[AfterRequestCallable] = ctx._after_request_functions
- for bp in request.blueprints:
- if bp in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
- if None in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[None]))
- for handler in funcs:
- response = self.ensure_sync(handler)(response)
- if not self.session_interface.is_null_session(ctx.session):
- self.session_interface.save_session(self, ctx.session, response)
- return response
-
- def do_teardown_request(
- self, exc: t.Optional[BaseException] = _sentinel # type: ignore
- ) -> None:
- """Called after the request is dispatched and the response is
- returned, right before the request context is popped.
-
- This calls all functions decorated with
- :meth:`teardown_request`, and :meth:`Blueprint.teardown_request`
- if a blueprint handled the request. Finally, the
- :data:`request_tearing_down` signal is sent.
-
- This is called by
- :meth:`RequestContext.pop() `,
- which may be delayed during testing to maintain access to
- resources.
-
- :param exc: An unhandled exception raised while dispatching the
- request. Detected from the current exception information if
- not passed. Passed to each teardown function.
-
- .. versionchanged:: 0.9
- Added the ``exc`` argument.
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- funcs: t.Iterable[TeardownCallable] = reversed(
- self.teardown_request_funcs[None]
- )
- for bp in request.blueprints:
- if bp in self.teardown_request_funcs:
- funcs = chain(funcs, reversed(self.teardown_request_funcs[bp]))
- for func in funcs:
- self.ensure_sync(func)(exc)
- request_tearing_down.send(self, exc=exc)
-
- def do_teardown_appcontext(
- self, exc: t.Optional[BaseException] = _sentinel # type: ignore
- ) -> None:
- """Called right before the application context is popped.
-
- When handling a request, the application context is popped
- after the request context. See :meth:`do_teardown_request`.
-
- This calls all functions decorated with
- :meth:`teardown_appcontext`. Then the
- :data:`appcontext_tearing_down` signal is sent.
-
- This is called by
- :meth:`AppContext.pop() `.
-
- .. versionadded:: 0.9
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- for func in reversed(self.teardown_appcontext_funcs):
- self.ensure_sync(func)(exc)
- appcontext_tearing_down.send(self, exc=exc)
-
- def app_context(self) -> AppContext:
- """Create an :class:`~flask.ctx.AppContext`. Use as a ``with``
- block to push the context, which will make :data:`current_app`
- point at this application.
-
- An application context is automatically pushed by
- :meth:`RequestContext.push() `
- when handling a request, and when running a CLI command. Use
- this to manually create a context outside of these situations.
-
- ::
-
- with app.app_context():
- init_db()
-
- See :doc:`/appcontext`.
-
- .. versionadded:: 0.9
- """
- return AppContext(self)
-
- def request_context(self, environ: dict) -> RequestContext:
- """Create a :class:`~flask.ctx.RequestContext` representing a
- WSGI environment. Use a ``with`` block to push the context,
- which will make :data:`request` point at this request.
-
- See :doc:`/reqcontext`.
-
- Typically you should not call this from your own code. A request
- context is automatically pushed by the :meth:`wsgi_app` when
- handling a request. Use :meth:`test_request_context` to create
- an environment and context instead of this method.
-
- :param environ: a WSGI environment
- """
- return RequestContext(self, environ)
-
- def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext:
- """Create a :class:`~flask.ctx.RequestContext` for a WSGI
- environment created from the given values. This is mostly useful
- during testing, where you may want to run a function that uses
- request data without dispatching a full request.
-
- See :doc:`/reqcontext`.
-
- Use a ``with`` block to push the context, which will make
- :data:`request` point at the request for the created
- environment. ::
-
- with test_request_context(...):
- generate_report()
-
- When using the shell, it may be easier to push and pop the
- context manually to avoid indentation. ::
-
- ctx = app.test_request_context(...)
- ctx.push()
- ...
- ctx.pop()
-
- Takes the same arguments as Werkzeug's
- :class:`~werkzeug.test.EnvironBuilder`, with some defaults from
- the application. See the linked Werkzeug docs for most of the
- available arguments. Flask-specific behavior is listed here.
-
- :param path: URL path being requested.
- :param base_url: Base URL where the app is being served, which
- ``path`` is relative to. If not given, built from
- :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
- :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
- :param subdomain: Subdomain name to append to
- :data:`SERVER_NAME`.
- :param url_scheme: Scheme to use instead of
- :data:`PREFERRED_URL_SCHEME`.
- :param data: The request body, either as a string or a dict of
- form keys and values.
- :param json: If given, this is serialized as JSON and passed as
- ``data``. Also defaults ``content_type`` to
- ``application/json``.
- :param args: other positional arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- :param kwargs: other keyword arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- """
- from .testing import EnvironBuilder
-
- builder = EnvironBuilder(self, *args, **kwargs)
-
- try:
- return self.request_context(builder.get_environ())
- finally:
- builder.close()
-
- def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
- """The actual WSGI application. This is not implemented in
- :meth:`__call__` so that middlewares can be applied without
- losing a reference to the app object. Instead of doing this::
-
- app = MyMiddleware(app)
-
- It's a better idea to do this instead::
-
- app.wsgi_app = MyMiddleware(app.wsgi_app)
-
- Then you still have the original application object around and
- can continue to call methods on it.
-
- .. versionchanged:: 0.7
- Teardown events for the request and app contexts are called
- even if an unhandled error occurs. Other events may not be
- called depending on when an error occurs during dispatch.
- See :ref:`callbacks-and-errors`.
-
- :param environ: A WSGI environment.
- :param start_response: A callable accepting a status code,
- a list of headers, and an optional exception context to
- start the response.
- """
- ctx = self.request_context(environ)
- error: t.Optional[BaseException] = None
- try:
- try:
- ctx.push()
- response = self.full_dispatch_request()
- except Exception as e:
- error = e
- response = self.handle_exception(e)
- except: # noqa: B001
- error = sys.exc_info()[1]
- raise
- return response(environ, start_response)
- finally:
- if self.should_ignore_error(error):
- error = None
- ctx.auto_pop(error)
-
- def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:
- """The WSGI server calls the Flask application object as the
- WSGI application. This calls :meth:`wsgi_app`, which can be
- wrapped to apply middleware.
- """
- return self.wsgi_app(environ, start_response)
diff --git a/venv/lib/python3.9/site-packages/flask/blueprints.py b/venv/lib/python3.9/site-packages/flask/blueprints.py
deleted file mode 100644
index f3913b3..0000000
--- a/venv/lib/python3.9/site-packages/flask/blueprints.py
+++ /dev/null
@@ -1,603 +0,0 @@
-import typing as t
-from collections import defaultdict
-from functools import update_wrapper
-
-from .scaffold import _endpoint_from_view_func
-from .scaffold import _sentinel
-from .scaffold import Scaffold
-from .typing import AfterRequestCallable
-from .typing import BeforeRequestCallable
-from .typing import ErrorHandlerCallable
-from .typing import TeardownCallable
-from .typing import TemplateContextProcessorCallable
-from .typing import TemplateFilterCallable
-from .typing import TemplateGlobalCallable
-from .typing import TemplateTestCallable
-from .typing import URLDefaultCallable
-from .typing import URLValuePreprocessorCallable
-
-if t.TYPE_CHECKING:
- from .app import Flask
-
-DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable]
-
-
-class BlueprintSetupState:
- """Temporary holder object for registering a blueprint with the
- application. An instance of this class is created by the
- :meth:`~flask.Blueprint.make_setup_state` method and later passed
- to all register callback functions.
- """
-
- def __init__(
- self,
- blueprint: "Blueprint",
- app: "Flask",
- options: t.Any,
- first_registration: bool,
- ) -> None:
- #: a reference to the current application
- self.app = app
-
- #: a reference to the blueprint that created this setup state.
- self.blueprint = blueprint
-
- #: a dictionary with all options that were passed to the
- #: :meth:`~flask.Flask.register_blueprint` method.
- self.options = options
-
- #: as blueprints can be registered multiple times with the
- #: application and not everything wants to be registered
- #: multiple times on it, this attribute can be used to figure
- #: out if the blueprint was registered in the past already.
- self.first_registration = first_registration
-
- subdomain = self.options.get("subdomain")
- if subdomain is None:
- subdomain = self.blueprint.subdomain
-
- #: The subdomain that the blueprint should be active for, ``None``
- #: otherwise.
- self.subdomain = subdomain
-
- url_prefix = self.options.get("url_prefix")
- if url_prefix is None:
- url_prefix = self.blueprint.url_prefix
- #: The prefix that should be used for all URLs defined on the
- #: blueprint.
- self.url_prefix = url_prefix
-
- self.name = self.options.get("name", blueprint.name)
- self.name_prefix = self.options.get("name_prefix", "")
-
- #: A dictionary with URL defaults that is added to each and every
- #: URL that was defined with the blueprint.
- self.url_defaults = dict(self.blueprint.url_values_defaults)
- self.url_defaults.update(self.options.get("url_defaults", ()))
-
- def add_url_rule(
- self,
- rule: str,
- endpoint: t.Optional[str] = None,
- view_func: t.Optional[t.Callable] = None,
- **options: t.Any,
- ) -> None:
- """A helper method to register a rule (and optionally a view function)
- to the application. The endpoint is automatically prefixed with the
- blueprint's name.
- """
- if self.url_prefix is not None:
- if rule:
- rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/")))
- else:
- rule = self.url_prefix
- options.setdefault("subdomain", self.subdomain)
- if endpoint is None:
- endpoint = _endpoint_from_view_func(view_func) # type: ignore
- defaults = self.url_defaults
- if "defaults" in options:
- defaults = dict(defaults, **options.pop("defaults"))
-
- self.app.add_url_rule(
- rule,
- f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."),
- view_func,
- defaults=defaults,
- **options,
- )
-
-
-class Blueprint(Scaffold):
- """Represents a blueprint, a collection of routes and other
- app-related functions that can be registered on a real application
- later.
-
- A blueprint is an object that allows defining application functions
- without requiring an application object ahead of time. It uses the
- same decorators as :class:`~flask.Flask`, but defers the need for an
- application by recording them for later registration.
-
- Decorating a function with a blueprint creates a deferred function
- that is called with :class:`~flask.blueprints.BlueprintSetupState`
- when the blueprint is registered on an application.
-
- See :doc:`/blueprints` for more information.
-
- :param name: The name of the blueprint. Will be prepended to each
- endpoint name.
- :param import_name: The name of the blueprint package, usually
- ``__name__``. This helps locate the ``root_path`` for the
- blueprint.
- :param static_folder: A folder with static files that should be
- served by the blueprint's static route. The path is relative to
- the blueprint's root path. Blueprint static files are disabled
- by default.
- :param static_url_path: The url to serve static files from.
- Defaults to ``static_folder``. If the blueprint does not have
- a ``url_prefix``, the app's static route will take precedence,
- and the blueprint's static files won't be accessible.
- :param template_folder: A folder with templates that should be added
- to the app's template search path. The path is relative to the
- blueprint's root path. Blueprint templates are disabled by
- default. Blueprint templates have a lower precedence than those
- in the app's templates folder.
- :param url_prefix: A path to prepend to all of the blueprint's URLs,
- to make them distinct from the rest of the app's routes.
- :param subdomain: A subdomain that blueprint routes will match on by
- default.
- :param url_defaults: A dict of default values that blueprint routes
- will receive by default.
- :param root_path: By default, the blueprint will automatically set
- this based on ``import_name``. In certain situations this
- automatic detection can fail, so the path can be specified
- manually instead.
-
- .. versionchanged:: 1.1.0
- Blueprints have a ``cli`` group to register nested CLI commands.
- The ``cli_group`` parameter controls the name of the group under
- the ``flask`` command.
-
- .. versionadded:: 0.7
- """
-
- warn_on_modifications = False
- _got_registered_once = False
-
- #: Blueprint local JSON encoder class to use. Set to ``None`` to use
- #: the app's :class:`~flask.Flask.json_encoder`.
- json_encoder = None
- #: Blueprint local JSON decoder class to use. Set to ``None`` to use
- #: the app's :class:`~flask.Flask.json_decoder`.
- json_decoder = None
-
- def __init__(
- self,
- name: str,
- import_name: str,
- static_folder: t.Optional[str] = None,
- static_url_path: t.Optional[str] = None,
- template_folder: t.Optional[str] = None,
- url_prefix: t.Optional[str] = None,
- subdomain: t.Optional[str] = None,
- url_defaults: t.Optional[dict] = None,
- root_path: t.Optional[str] = None,
- cli_group: t.Optional[str] = _sentinel, # type: ignore
- ):
- super().__init__(
- import_name=import_name,
- static_folder=static_folder,
- static_url_path=static_url_path,
- template_folder=template_folder,
- root_path=root_path,
- )
-
- if "." in name:
- raise ValueError("'name' may not contain a dot '.' character.")
-
- self.name = name
- self.url_prefix = url_prefix
- self.subdomain = subdomain
- self.deferred_functions: t.List[DeferredSetupFunction] = []
-
- if url_defaults is None:
- url_defaults = {}
-
- self.url_values_defaults = url_defaults
- self.cli_group = cli_group
- self._blueprints: t.List[t.Tuple["Blueprint", dict]] = []
-
- def _is_setup_finished(self) -> bool:
- return self.warn_on_modifications and self._got_registered_once
-
- def record(self, func: t.Callable) -> None:
- """Registers a function that is called when the blueprint is
- registered on the application. This function is called with the
- state as argument as returned by the :meth:`make_setup_state`
- method.
- """
- if self._got_registered_once and self.warn_on_modifications:
- from warnings import warn
-
- warn(
- Warning(
- "The blueprint was already registered once but is"
- " getting modified now. These changes will not show"
- " up."
- )
- )
- self.deferred_functions.append(func)
-
- def record_once(self, func: t.Callable) -> None:
- """Works like :meth:`record` but wraps the function in another
- function that will ensure the function is only called once. If the
- blueprint is registered a second time on the application, the
- function passed is not called.
- """
-
- def wrapper(state: BlueprintSetupState) -> None:
- if state.first_registration:
- func(state)
-
- return self.record(update_wrapper(wrapper, func))
-
- def make_setup_state(
- self, app: "Flask", options: dict, first_registration: bool = False
- ) -> BlueprintSetupState:
- """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState`
- object that is later passed to the register callback functions.
- Subclasses can override this to return a subclass of the setup state.
- """
- return BlueprintSetupState(self, app, options, first_registration)
-
- def register_blueprint(self, blueprint: "Blueprint", **options: t.Any) -> None:
- """Register a :class:`~flask.Blueprint` on this blueprint. Keyword
- arguments passed to this method will override the defaults set
- on the blueprint.
-
- .. versionchanged:: 2.0.1
- The ``name`` option can be used to change the (pre-dotted)
- name the blueprint is registered with. This allows the same
- blueprint to be registered multiple times with unique names
- for ``url_for``.
-
- .. versionadded:: 2.0
- """
- if blueprint is self:
- raise ValueError("Cannot register a blueprint on itself")
- self._blueprints.append((blueprint, options))
-
- def register(self, app: "Flask", options: dict) -> None:
- """Called by :meth:`Flask.register_blueprint` to register all
- views and callbacks registered on the blueprint with the
- application. Creates a :class:`.BlueprintSetupState` and calls
- each :meth:`record` callback with it.
-
- :param app: The application this blueprint is being registered
- with.
- :param options: Keyword arguments forwarded from
- :meth:`~Flask.register_blueprint`.
-
- .. versionchanged:: 2.0.1
- Nested blueprints are registered with their dotted name.
- This allows different blueprints with the same name to be
- nested at different locations.
-
- .. versionchanged:: 2.0.1
- The ``name`` option can be used to change the (pre-dotted)
- name the blueprint is registered with. This allows the same
- blueprint to be registered multiple times with unique names
- for ``url_for``.
-
- .. versionchanged:: 2.0.1
- Registering the same blueprint with the same name multiple
- times is deprecated and will become an error in Flask 2.1.
- """
- first_registration = not any(bp is self for bp in app.blueprints.values())
- name_prefix = options.get("name_prefix", "")
- self_name = options.get("name", self.name)
- name = f"{name_prefix}.{self_name}".lstrip(".")
-
- if name in app.blueprints:
- existing_at = f" '{name}'" if self_name != name else ""
-
- if app.blueprints[name] is not self:
- raise ValueError(
- f"The name '{self_name}' is already registered for"
- f" a different blueprint{existing_at}. Use 'name='"
- " to provide a unique name."
- )
- else:
- import warnings
-
- warnings.warn(
- f"The name '{self_name}' is already registered for"
- f" this blueprint{existing_at}. Use 'name=' to"
- " provide a unique name. This will become an error"
- " in Flask 2.1.",
- stacklevel=4,
- )
-
- app.blueprints[name] = self
- self._got_registered_once = True
- state = self.make_setup_state(app, options, first_registration)
-
- if self.has_static_folder:
- state.add_url_rule(
- f"{self.static_url_path}/",
- view_func=self.send_static_file,
- endpoint="static",
- )
-
- # Merge blueprint data into parent.
- if first_registration:
-
- def extend(bp_dict, parent_dict):
- for key, values in bp_dict.items():
- key = name if key is None else f"{name}.{key}"
- parent_dict[key].extend(values)
-
- for key, value in self.error_handler_spec.items():
- key = name if key is None else f"{name}.{key}"
- value = defaultdict(
- dict,
- {
- code: {
- exc_class: func for exc_class, func in code_values.items()
- }
- for code, code_values in value.items()
- },
- )
- app.error_handler_spec[key] = value
-
- for endpoint, func in self.view_functions.items():
- app.view_functions[endpoint] = func
-
- extend(self.before_request_funcs, app.before_request_funcs)
- extend(self.after_request_funcs, app.after_request_funcs)
- extend(
- self.teardown_request_funcs,
- app.teardown_request_funcs,
- )
- extend(self.url_default_functions, app.url_default_functions)
- extend(self.url_value_preprocessors, app.url_value_preprocessors)
- extend(self.template_context_processors, app.template_context_processors)
-
- for deferred in self.deferred_functions:
- deferred(state)
-
- cli_resolved_group = options.get("cli_group", self.cli_group)
-
- if self.cli.commands:
- if cli_resolved_group is None:
- app.cli.commands.update(self.cli.commands)
- elif cli_resolved_group is _sentinel:
- self.cli.name = name
- app.cli.add_command(self.cli)
- else:
- self.cli.name = cli_resolved_group
- app.cli.add_command(self.cli)
-
- for blueprint, bp_options in self._blueprints:
- bp_options = bp_options.copy()
- bp_url_prefix = bp_options.get("url_prefix")
-
- if bp_url_prefix is None:
- bp_url_prefix = blueprint.url_prefix
-
- if state.url_prefix is not None and bp_url_prefix is not None:
- bp_options["url_prefix"] = (
- state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/")
- )
- elif bp_url_prefix is not None:
- bp_options["url_prefix"] = bp_url_prefix
- elif state.url_prefix is not None:
- bp_options["url_prefix"] = state.url_prefix
-
- bp_options["name_prefix"] = name
- blueprint.register(app, bp_options)
-
- def add_url_rule(
- self,
- rule: str,
- endpoint: t.Optional[str] = None,
- view_func: t.Optional[t.Callable] = None,
- provide_automatic_options: t.Optional[bool] = None,
- **options: t.Any,
- ) -> None:
- """Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for
- the :func:`url_for` function is prefixed with the name of the blueprint.
- """
- if endpoint and "." in endpoint:
- raise ValueError("'endpoint' may not contain a dot '.' character.")
-
- if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__:
- raise ValueError("'view_func' name may not contain a dot '.' character.")
-
- self.record(
- lambda s: s.add_url_rule(
- rule,
- endpoint,
- view_func,
- provide_automatic_options=provide_automatic_options,
- **options,
- )
- )
-
- def app_template_filter(
- self, name: t.Optional[str] = None
- ) -> t.Callable[[TemplateFilterCallable], TemplateFilterCallable]:
- """Register a custom template filter, available application wide. Like
- :meth:`Flask.template_filter` but for a blueprint.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
-
- def decorator(f: TemplateFilterCallable) -> TemplateFilterCallable:
- self.add_app_template_filter(f, name=name)
- return f
-
- return decorator
-
- def add_app_template_filter(
- self, f: TemplateFilterCallable, name: t.Optional[str] = None
- ) -> None:
- """Register a custom template filter, available application wide. Like
- :meth:`Flask.add_template_filter` but for a blueprint. Works exactly
- like the :meth:`app_template_filter` decorator.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
-
- def register_template(state: BlueprintSetupState) -> None:
- state.app.jinja_env.filters[name or f.__name__] = f
-
- self.record_once(register_template)
-
- def app_template_test(
- self, name: t.Optional[str] = None
- ) -> t.Callable[[TemplateTestCallable], TemplateTestCallable]:
- """Register a custom template test, available application wide. Like
- :meth:`Flask.template_test` but for a blueprint.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
-
- def decorator(f: TemplateTestCallable) -> TemplateTestCallable:
- self.add_app_template_test(f, name=name)
- return f
-
- return decorator
-
- def add_app_template_test(
- self, f: TemplateTestCallable, name: t.Optional[str] = None
- ) -> None:
- """Register a custom template test, available application wide. Like
- :meth:`Flask.add_template_test` but for a blueprint. Works exactly
- like the :meth:`app_template_test` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
-
- def register_template(state: BlueprintSetupState) -> None:
- state.app.jinja_env.tests[name or f.__name__] = f
-
- self.record_once(register_template)
-
- def app_template_global(
- self, name: t.Optional[str] = None
- ) -> t.Callable[[TemplateGlobalCallable], TemplateGlobalCallable]:
- """Register a custom template global, available application wide. Like
- :meth:`Flask.template_global` but for a blueprint.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global, otherwise the
- function name will be used.
- """
-
- def decorator(f: TemplateGlobalCallable) -> TemplateGlobalCallable:
- self.add_app_template_global(f, name=name)
- return f
-
- return decorator
-
- def add_app_template_global(
- self, f: TemplateGlobalCallable, name: t.Optional[str] = None
- ) -> None:
- """Register a custom template global, available application wide. Like
- :meth:`Flask.add_template_global` but for a blueprint. Works exactly
- like the :meth:`app_template_global` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global, otherwise the
- function name will be used.
- """
-
- def register_template(state: BlueprintSetupState) -> None:
- state.app.jinja_env.globals[name or f.__name__] = f
-
- self.record_once(register_template)
-
- def before_app_request(self, f: BeforeRequestCallable) -> BeforeRequestCallable:
- """Like :meth:`Flask.before_request`. Such a function is executed
- before each request, even if outside of a blueprint.
- """
- self.record_once(
- lambda s: s.app.before_request_funcs.setdefault(None, []).append(f)
- )
- return f
-
- def before_app_first_request(
- self, f: BeforeRequestCallable
- ) -> BeforeRequestCallable:
- """Like :meth:`Flask.before_first_request`. Such a function is
- executed before the first request to the application.
- """
- self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
- return f
-
- def after_app_request(self, f: AfterRequestCallable) -> AfterRequestCallable:
- """Like :meth:`Flask.after_request` but for a blueprint. Such a function
- is executed after each request, even if outside of the blueprint.
- """
- self.record_once(
- lambda s: s.app.after_request_funcs.setdefault(None, []).append(f)
- )
- return f
-
- def teardown_app_request(self, f: TeardownCallable) -> TeardownCallable:
- """Like :meth:`Flask.teardown_request` but for a blueprint. Such a
- function is executed when tearing down each request, even if outside of
- the blueprint.
- """
- self.record_once(
- lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f)
- )
- return f
-
- def app_context_processor(
- self, f: TemplateContextProcessorCallable
- ) -> TemplateContextProcessorCallable:
- """Like :meth:`Flask.context_processor` but for a blueprint. Such a
- function is executed each request, even if outside of the blueprint.
- """
- self.record_once(
- lambda s: s.app.template_context_processors.setdefault(None, []).append(f)
- )
- return f
-
- def app_errorhandler(self, code: t.Union[t.Type[Exception], int]) -> t.Callable:
- """Like :meth:`Flask.errorhandler` but for a blueprint. This
- handler is used for all requests, even if outside of the blueprint.
- """
-
- def decorator(f: ErrorHandlerCallable) -> ErrorHandlerCallable:
- self.record_once(lambda s: s.app.errorhandler(code)(f))
- return f
-
- return decorator
-
- def app_url_value_preprocessor(
- self, f: URLValuePreprocessorCallable
- ) -> URLValuePreprocessorCallable:
- """Same as :meth:`url_value_preprocessor` but application wide."""
- self.record_once(
- lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f)
- )
- return f
-
- def app_url_defaults(self, f: URLDefaultCallable) -> URLDefaultCallable:
- """Same as :meth:`url_defaults` but application wide."""
- self.record_once(
- lambda s: s.app.url_default_functions.setdefault(None, []).append(f)
- )
- return f
diff --git a/venv/lib/python3.9/site-packages/flask/cli.py b/venv/lib/python3.9/site-packages/flask/cli.py
deleted file mode 100644
index d9e810d..0000000
--- a/venv/lib/python3.9/site-packages/flask/cli.py
+++ /dev/null
@@ -1,994 +0,0 @@
-import ast
-import inspect
-import os
-import platform
-import re
-import sys
-import traceback
-import warnings
-from functools import update_wrapper
-from operator import attrgetter
-from threading import Lock
-from threading import Thread
-
-import click
-from werkzeug.utils import import_string
-
-from .globals import current_app
-from .helpers import get_debug_flag
-from .helpers import get_env
-from .helpers import get_load_dotenv
-
-try:
- import dotenv
-except ImportError:
- dotenv = None
-
-try:
- import ssl
-except ImportError:
- ssl = None # type: ignore
-
-
-class NoAppException(click.UsageError):
- """Raised if an application cannot be found or loaded."""
-
-
-def find_best_app(script_info, module):
- """Given a module instance this tries to find the best possible
- application in the module or raises an exception.
- """
- from . import Flask
-
- # Search for the most common names first.
- for attr_name in ("app", "application"):
- app = getattr(module, attr_name, None)
-
- if isinstance(app, Flask):
- return app
-
- # Otherwise find the only object that is a Flask instance.
- matches = [v for v in module.__dict__.values() if isinstance(v, Flask)]
-
- if len(matches) == 1:
- return matches[0]
- elif len(matches) > 1:
- raise NoAppException(
- "Detected multiple Flask applications in module"
- f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
- f" to specify the correct one."
- )
-
- # Search for app factory functions.
- for attr_name in ("create_app", "make_app"):
- app_factory = getattr(module, attr_name, None)
-
- if inspect.isfunction(app_factory):
- try:
- app = call_factory(script_info, app_factory)
-
- if isinstance(app, Flask):
- return app
- except TypeError:
- if not _called_with_wrong_args(app_factory):
- raise
- raise NoAppException(
- f"Detected factory {attr_name!r} in module {module.__name__!r},"
- " but could not call it without arguments. Use"
- f" \"FLASK_APP='{module.__name__}:{attr_name}(args)'\""
- " to specify arguments."
- )
-
- raise NoAppException(
- "Failed to find Flask application or factory in module"
- f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
- " to specify one."
- )
-
-
-def call_factory(script_info, app_factory, args=None, kwargs=None):
- """Takes an app factory, a ``script_info` object and optionally a tuple
- of arguments. Checks for the existence of a script_info argument and calls
- the app_factory depending on that and the arguments provided.
- """
- sig = inspect.signature(app_factory)
- args = [] if args is None else args
- kwargs = {} if kwargs is None else kwargs
-
- if "script_info" in sig.parameters:
- warnings.warn(
- "The 'script_info' argument is deprecated and will not be"
- " passed to the app factory function in Flask 2.1.",
- DeprecationWarning,
- )
- kwargs["script_info"] = script_info
-
- if (
- not args
- and len(sig.parameters) == 1
- and next(iter(sig.parameters.values())).default is inspect.Parameter.empty
- ):
- warnings.warn(
- "Script info is deprecated and will not be passed as the"
- " single argument to the app factory function in Flask"
- " 2.1.",
- DeprecationWarning,
- )
- args.append(script_info)
-
- return app_factory(*args, **kwargs)
-
-
-def _called_with_wrong_args(f):
- """Check whether calling a function raised a ``TypeError`` because
- the call failed or because something in the factory raised the
- error.
-
- :param f: The function that was called.
- :return: ``True`` if the call failed.
- """
- tb = sys.exc_info()[2]
-
- try:
- while tb is not None:
- if tb.tb_frame.f_code is f.__code__:
- # In the function, it was called successfully.
- return False
-
- tb = tb.tb_next
-
- # Didn't reach the function.
- return True
- finally:
- # Delete tb to break a circular reference.
- # https://docs.python.org/2/library/sys.html#sys.exc_info
- del tb
-
-
-def find_app_by_string(script_info, module, app_name):
- """Check if the given string is a variable name or a function. Call
- a function to get the app instance, or return the variable directly.
- """
- from . import Flask
-
- # Parse app_name as a single expression to determine if it's a valid
- # attribute name or function call.
- try:
- expr = ast.parse(app_name.strip(), mode="eval").body
- except SyntaxError:
- raise NoAppException(
- f"Failed to parse {app_name!r} as an attribute name or function call."
- )
-
- if isinstance(expr, ast.Name):
- name = expr.id
- args = kwargs = None
- elif isinstance(expr, ast.Call):
- # Ensure the function name is an attribute name only.
- if not isinstance(expr.func, ast.Name):
- raise NoAppException(
- f"Function reference must be a simple name: {app_name!r}."
- )
-
- name = expr.func.id
-
- # Parse the positional and keyword arguments as literals.
- try:
- args = [ast.literal_eval(arg) for arg in expr.args]
- kwargs = {kw.arg: ast.literal_eval(kw.value) for kw in expr.keywords}
- except ValueError:
- # literal_eval gives cryptic error messages, show a generic
- # message with the full expression instead.
- raise NoAppException(
- f"Failed to parse arguments as literal values: {app_name!r}."
- )
- else:
- raise NoAppException(
- f"Failed to parse {app_name!r} as an attribute name or function call."
- )
-
- try:
- attr = getattr(module, name)
- except AttributeError:
- raise NoAppException(
- f"Failed to find attribute {name!r} in {module.__name__!r}."
- )
-
- # If the attribute is a function, call it with any args and kwargs
- # to get the real application.
- if inspect.isfunction(attr):
- try:
- app = call_factory(script_info, attr, args, kwargs)
- except TypeError:
- if not _called_with_wrong_args(attr):
- raise
-
- raise NoAppException(
- f"The factory {app_name!r} in module"
- f" {module.__name__!r} could not be called with the"
- " specified arguments."
- )
- else:
- app = attr
-
- if isinstance(app, Flask):
- return app
-
- raise NoAppException(
- "A valid Flask application was not obtained from"
- f" '{module.__name__}:{app_name}'."
- )
-
-
-def prepare_import(path):
- """Given a filename this will try to calculate the python path, add it
- to the search path and return the actual module name that is expected.
- """
- path = os.path.realpath(path)
-
- fname, ext = os.path.splitext(path)
- if ext == ".py":
- path = fname
-
- if os.path.basename(path) == "__init__":
- path = os.path.dirname(path)
-
- module_name = []
-
- # move up until outside package structure (no __init__.py)
- while True:
- path, name = os.path.split(path)
- module_name.append(name)
-
- if not os.path.exists(os.path.join(path, "__init__.py")):
- break
-
- if sys.path[0] != path:
- sys.path.insert(0, path)
-
- return ".".join(module_name[::-1])
-
-
-def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
- __traceback_hide__ = True # noqa: F841
-
- try:
- __import__(module_name)
- except ImportError:
- # Reraise the ImportError if it occurred within the imported module.
- # Determine this by checking whether the trace has a depth > 1.
- if sys.exc_info()[2].tb_next:
- raise NoAppException(
- f"While importing {module_name!r}, an ImportError was"
- f" raised:\n\n{traceback.format_exc()}"
- )
- elif raise_if_not_found:
- raise NoAppException(f"Could not import {module_name!r}.")
- else:
- return
-
- module = sys.modules[module_name]
-
- if app_name is None:
- return find_best_app(script_info, module)
- else:
- return find_app_by_string(script_info, module, app_name)
-
-
-def get_version(ctx, param, value):
- if not value or ctx.resilient_parsing:
- return
-
- import werkzeug
- from . import __version__
-
- click.echo(
- f"Python {platform.python_version()}\n"
- f"Flask {__version__}\n"
- f"Werkzeug {werkzeug.__version__}",
- color=ctx.color,
- )
- ctx.exit()
-
-
-version_option = click.Option(
- ["--version"],
- help="Show the flask version",
- expose_value=False,
- callback=get_version,
- is_flag=True,
- is_eager=True,
-)
-
-
-class DispatchingApp:
- """Special application that dispatches to a Flask application which
- is imported by name in a background thread. If an error happens
- it is recorded and shown as part of the WSGI handling which in case
- of the Werkzeug debugger means that it shows up in the browser.
- """
-
- def __init__(self, loader, use_eager_loading=None):
- self.loader = loader
- self._app = None
- self._lock = Lock()
- self._bg_loading_exc_info = None
-
- if use_eager_loading is None:
- use_eager_loading = os.environ.get("WERKZEUG_RUN_MAIN") != "true"
-
- if use_eager_loading:
- self._load_unlocked()
- else:
- self._load_in_background()
-
- def _load_in_background(self):
- def _load_app():
- __traceback_hide__ = True # noqa: F841
- with self._lock:
- try:
- self._load_unlocked()
- except Exception:
- self._bg_loading_exc_info = sys.exc_info()
-
- t = Thread(target=_load_app, args=())
- t.start()
-
- def _flush_bg_loading_exception(self):
- __traceback_hide__ = True # noqa: F841
- exc_info = self._bg_loading_exc_info
- if exc_info is not None:
- self._bg_loading_exc_info = None
- raise exc_info
-
- def _load_unlocked(self):
- __traceback_hide__ = True # noqa: F841
- self._app = rv = self.loader()
- self._bg_loading_exc_info = None
- return rv
-
- def __call__(self, environ, start_response):
- __traceback_hide__ = True # noqa: F841
- if self._app is not None:
- return self._app(environ, start_response)
- self._flush_bg_loading_exception()
- with self._lock:
- if self._app is not None:
- rv = self._app
- else:
- rv = self._load_unlocked()
- return rv(environ, start_response)
-
-
-class ScriptInfo:
- """Helper object to deal with Flask applications. This is usually not
- necessary to interface with as it's used internally in the dispatching
- to click. In future versions of Flask this object will most likely play
- a bigger role. Typically it's created automatically by the
- :class:`FlaskGroup` but you can also manually create it and pass it
- onwards as click object.
- """
-
- def __init__(self, app_import_path=None, create_app=None, set_debug_flag=True):
- #: Optionally the import path for the Flask application.
- self.app_import_path = app_import_path or os.environ.get("FLASK_APP")
- #: Optionally a function that is passed the script info to create
- #: the instance of the application.
- self.create_app = create_app
- #: A dictionary with arbitrary data that can be associated with
- #: this script info.
- self.data = {}
- self.set_debug_flag = set_debug_flag
- self._loaded_app = None
-
- def load_app(self):
- """Loads the Flask app (if not yet loaded) and returns it. Calling
- this multiple times will just result in the already loaded app to
- be returned.
- """
- __traceback_hide__ = True # noqa: F841
-
- if self._loaded_app is not None:
- return self._loaded_app
-
- if self.create_app is not None:
- app = call_factory(self, self.create_app)
- else:
- if self.app_import_path:
- path, name = (
- re.split(r":(?![\\/])", self.app_import_path, 1) + [None]
- )[:2]
- import_name = prepare_import(path)
- app = locate_app(self, import_name, name)
- else:
- for path in ("wsgi.py", "app.py"):
- import_name = prepare_import(path)
- app = locate_app(self, import_name, None, raise_if_not_found=False)
-
- if app:
- break
-
- if not app:
- raise NoAppException(
- "Could not locate a Flask application. You did not provide "
- 'the "FLASK_APP" environment variable, and a "wsgi.py" or '
- '"app.py" module was not found in the current directory.'
- )
-
- if self.set_debug_flag:
- # Update the app's debug flag through the descriptor so that
- # other values repopulate as well.
- app.debug = get_debug_flag()
-
- self._loaded_app = app
- return app
-
-
-pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True)
-
-
-def with_appcontext(f):
- """Wraps a callback so that it's guaranteed to be executed with the
- script's application context. If callbacks are registered directly
- to the ``app.cli`` object then they are wrapped with this function
- by default unless it's disabled.
- """
-
- @click.pass_context
- def decorator(__ctx, *args, **kwargs):
- with __ctx.ensure_object(ScriptInfo).load_app().app_context():
- return __ctx.invoke(f, *args, **kwargs)
-
- return update_wrapper(decorator, f)
-
-
-class AppGroup(click.Group):
- """This works similar to a regular click :class:`~click.Group` but it
- changes the behavior of the :meth:`command` decorator so that it
- automatically wraps the functions in :func:`with_appcontext`.
-
- Not to be confused with :class:`FlaskGroup`.
- """
-
- def command(self, *args, **kwargs):
- """This works exactly like the method of the same name on a regular
- :class:`click.Group` but it wraps callbacks in :func:`with_appcontext`
- unless it's disabled by passing ``with_appcontext=False``.
- """
- wrap_for_ctx = kwargs.pop("with_appcontext", True)
-
- def decorator(f):
- if wrap_for_ctx:
- f = with_appcontext(f)
- return click.Group.command(self, *args, **kwargs)(f)
-
- return decorator
-
- def group(self, *args, **kwargs):
- """This works exactly like the method of the same name on a regular
- :class:`click.Group` but it defaults the group class to
- :class:`AppGroup`.
- """
- kwargs.setdefault("cls", AppGroup)
- return click.Group.group(self, *args, **kwargs)
-
-
-class FlaskGroup(AppGroup):
- """Special subclass of the :class:`AppGroup` group that supports
- loading more commands from the configured Flask app. Normally a
- developer does not have to interface with this class but there are
- some very advanced use cases for which it makes sense to create an
- instance of this. see :ref:`custom-scripts`.
-
- :param add_default_commands: if this is True then the default run and
- shell commands will be added.
- :param add_version_option: adds the ``--version`` option.
- :param create_app: an optional callback that is passed the script info and
- returns the loaded app.
- :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
- files to set environment variables. Will also change the working
- directory to the directory containing the first file found.
- :param set_debug_flag: Set the app's debug flag based on the active
- environment
-
- .. versionchanged:: 1.0
- If installed, python-dotenv will be used to load environment variables
- from :file:`.env` and :file:`.flaskenv` files.
- """
-
- def __init__(
- self,
- add_default_commands=True,
- create_app=None,
- add_version_option=True,
- load_dotenv=True,
- set_debug_flag=True,
- **extra,
- ):
- params = list(extra.pop("params", None) or ())
-
- if add_version_option:
- params.append(version_option)
-
- AppGroup.__init__(self, params=params, **extra)
- self.create_app = create_app
- self.load_dotenv = load_dotenv
- self.set_debug_flag = set_debug_flag
-
- if add_default_commands:
- self.add_command(run_command)
- self.add_command(shell_command)
- self.add_command(routes_command)
-
- self._loaded_plugin_commands = False
-
- def _load_plugin_commands(self):
- if self._loaded_plugin_commands:
- return
- try:
- import pkg_resources
- except ImportError:
- self._loaded_plugin_commands = True
- return
-
- for ep in pkg_resources.iter_entry_points("flask.commands"):
- self.add_command(ep.load(), ep.name)
- self._loaded_plugin_commands = True
-
- def get_command(self, ctx, name):
- self._load_plugin_commands()
- # Look up built-in and plugin commands, which should be
- # available even if the app fails to load.
- rv = super().get_command(ctx, name)
-
- if rv is not None:
- return rv
-
- info = ctx.ensure_object(ScriptInfo)
-
- # Look up commands provided by the app, showing an error and
- # continuing if the app couldn't be loaded.
- try:
- return info.load_app().cli.get_command(ctx, name)
- except NoAppException as e:
- click.secho(f"Error: {e.format_message()}\n", err=True, fg="red")
-
- def list_commands(self, ctx):
- self._load_plugin_commands()
- # Start with the built-in and plugin commands.
- rv = set(super().list_commands(ctx))
- info = ctx.ensure_object(ScriptInfo)
-
- # Add commands provided by the app, showing an error and
- # continuing if the app couldn't be loaded.
- try:
- rv.update(info.load_app().cli.list_commands(ctx))
- except NoAppException as e:
- # When an app couldn't be loaded, show the error message
- # without the traceback.
- click.secho(f"Error: {e.format_message()}\n", err=True, fg="red")
- except Exception:
- # When any other errors occurred during loading, show the
- # full traceback.
- click.secho(f"{traceback.format_exc()}\n", err=True, fg="red")
-
- return sorted(rv)
-
- def main(self, *args, **kwargs):
- # Set a global flag that indicates that we were invoked from the
- # command line interface. This is detected by Flask.run to make the
- # call into a no-op. This is necessary to avoid ugly errors when the
- # script that is loaded here also attempts to start a server.
- os.environ["FLASK_RUN_FROM_CLI"] = "true"
-
- if get_load_dotenv(self.load_dotenv):
- load_dotenv()
-
- obj = kwargs.get("obj")
-
- if obj is None:
- obj = ScriptInfo(
- create_app=self.create_app, set_debug_flag=self.set_debug_flag
- )
-
- kwargs["obj"] = obj
- kwargs.setdefault("auto_envvar_prefix", "FLASK")
- return super().main(*args, **kwargs)
-
-
-def _path_is_ancestor(path, other):
- """Take ``other`` and remove the length of ``path`` from it. Then join it
- to ``path``. If it is the original value, ``path`` is an ancestor of
- ``other``."""
- return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other
-
-
-def load_dotenv(path=None):
- """Load "dotenv" files in order of precedence to set environment variables.
-
- If an env var is already set it is not overwritten, so earlier files in the
- list are preferred over later files.
-
- This is a no-op if `python-dotenv`_ is not installed.
-
- .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
-
- :param path: Load the file at this location instead of searching.
- :return: ``True`` if a file was loaded.
-
- .. versionchanged:: 1.1.0
- Returns ``False`` when python-dotenv is not installed, or when
- the given path isn't a file.
-
- .. versionchanged:: 2.0
- When loading the env files, set the default encoding to UTF-8.
-
- .. versionadded:: 1.0
- """
- if dotenv is None:
- if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"):
- click.secho(
- " * Tip: There are .env or .flaskenv files present."
- ' Do "pip install python-dotenv" to use them.',
- fg="yellow",
- err=True,
- )
-
- return False
-
- # if the given path specifies the actual file then return True,
- # else False
- if path is not None:
- if os.path.isfile(path):
- return dotenv.load_dotenv(path, encoding="utf-8")
-
- return False
-
- new_dir = None
-
- for name in (".env", ".flaskenv"):
- path = dotenv.find_dotenv(name, usecwd=True)
-
- if not path:
- continue
-
- if new_dir is None:
- new_dir = os.path.dirname(path)
-
- dotenv.load_dotenv(path, encoding="utf-8")
-
- return new_dir is not None # at least one file was located and loaded
-
-
-def show_server_banner(env, debug, app_import_path, eager_loading):
- """Show extra startup messages the first time the server is run,
- ignoring the reloader.
- """
- if os.environ.get("WERKZEUG_RUN_MAIN") == "true":
- return
-
- if app_import_path is not None:
- message = f" * Serving Flask app {app_import_path!r}"
-
- if not eager_loading:
- message += " (lazy loading)"
-
- click.echo(message)
-
- click.echo(f" * Environment: {env}")
-
- if env == "production":
- click.secho(
- " WARNING: This is a development server. Do not use it in"
- " a production deployment.",
- fg="red",
- )
- click.secho(" Use a production WSGI server instead.", dim=True)
-
- if debug is not None:
- click.echo(f" * Debug mode: {'on' if debug else 'off'}")
-
-
-class CertParamType(click.ParamType):
- """Click option type for the ``--cert`` option. Allows either an
- existing file, the string ``'adhoc'``, or an import for a
- :class:`~ssl.SSLContext` object.
- """
-
- name = "path"
-
- def __init__(self):
- self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True)
-
- def convert(self, value, param, ctx):
- if ssl is None:
- raise click.BadParameter(
- 'Using "--cert" requires Python to be compiled with SSL support.',
- ctx,
- param,
- )
-
- try:
- return self.path_type(value, param, ctx)
- except click.BadParameter:
- value = click.STRING(value, param, ctx).lower()
-
- if value == "adhoc":
- try:
- import cryptography # noqa: F401
- except ImportError:
- raise click.BadParameter(
- "Using ad-hoc certificates requires the cryptography library.",
- ctx,
- param,
- )
-
- return value
-
- obj = import_string(value, silent=True)
-
- if isinstance(obj, ssl.SSLContext):
- return obj
-
- raise
-
-
-def _validate_key(ctx, param, value):
- """The ``--key`` option must be specified when ``--cert`` is a file.
- Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed.
- """
- cert = ctx.params.get("cert")
- is_adhoc = cert == "adhoc"
- is_context = ssl and isinstance(cert, ssl.SSLContext)
-
- if value is not None:
- if is_adhoc:
- raise click.BadParameter(
- 'When "--cert" is "adhoc", "--key" is not used.', ctx, param
- )
-
- if is_context:
- raise click.BadParameter(
- 'When "--cert" is an SSLContext object, "--key is not used.', ctx, param
- )
-
- if not cert:
- raise click.BadParameter('"--cert" must also be specified.', ctx, param)
-
- ctx.params["cert"] = cert, value
-
- else:
- if cert and not (is_adhoc or is_context):
- raise click.BadParameter('Required when using "--cert".', ctx, param)
-
- return value
-
-
-class SeparatedPathType(click.Path):
- """Click option type that accepts a list of values separated by the
- OS's path separator (``:``, ``;`` on Windows). Each value is
- validated as a :class:`click.Path` type.
- """
-
- def convert(self, value, param, ctx):
- items = self.split_envvar_value(value)
- super_convert = super().convert
- return [super_convert(item, param, ctx) for item in items]
-
-
-@click.command("run", short_help="Run a development server.")
-@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.")
-@click.option("--port", "-p", default=5000, help="The port to bind to.")
-@click.option(
- "--cert", type=CertParamType(), help="Specify a certificate file to use HTTPS."
-)
-@click.option(
- "--key",
- type=click.Path(exists=True, dir_okay=False, resolve_path=True),
- callback=_validate_key,
- expose_value=False,
- help="The key file to use when specifying a certificate.",
-)
-@click.option(
- "--reload/--no-reload",
- default=None,
- help="Enable or disable the reloader. By default the reloader "
- "is active if debug is enabled.",
-)
-@click.option(
- "--debugger/--no-debugger",
- default=None,
- help="Enable or disable the debugger. By default the debugger "
- "is active if debug is enabled.",
-)
-@click.option(
- "--eager-loading/--lazy-loading",
- default=None,
- help="Enable or disable eager loading. By default eager "
- "loading is enabled if the reloader is disabled.",
-)
-@click.option(
- "--with-threads/--without-threads",
- default=True,
- help="Enable or disable multithreading.",
-)
-@click.option(
- "--extra-files",
- default=None,
- type=SeparatedPathType(),
- help=(
- "Extra files that trigger a reload on change. Multiple paths"
- f" are separated by {os.path.pathsep!r}."
- ),
-)
-@pass_script_info
-def run_command(
- info, host, port, reload, debugger, eager_loading, with_threads, cert, extra_files
-):
- """Run a local development server.
-
- This server is for development purposes only. It does not provide
- the stability, security, or performance of production WSGI servers.
-
- The reloader and debugger are enabled by default if
- FLASK_ENV=development or FLASK_DEBUG=1.
- """
- debug = get_debug_flag()
-
- if reload is None:
- reload = debug
-
- if debugger is None:
- debugger = debug
-
- show_server_banner(get_env(), debug, info.app_import_path, eager_loading)
- app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
-
- from werkzeug.serving import run_simple
-
- run_simple(
- host,
- port,
- app,
- use_reloader=reload,
- use_debugger=debugger,
- threaded=with_threads,
- ssl_context=cert,
- extra_files=extra_files,
- )
-
-
-@click.command("shell", short_help="Run a shell in the app context.")
-@with_appcontext
-def shell_command() -> None:
- """Run an interactive Python shell in the context of a given
- Flask application. The application will populate the default
- namespace of this shell according to its configuration.
-
- This is useful for executing small snippets of management code
- without having to manually configure the application.
- """
- import code
- from .globals import _app_ctx_stack
-
- app = _app_ctx_stack.top.app
- banner = (
- f"Python {sys.version} on {sys.platform}\n"
- f"App: {app.import_name} [{app.env}]\n"
- f"Instance: {app.instance_path}"
- )
- ctx: dict = {}
-
- # Support the regular Python interpreter startup script if someone
- # is using it.
- startup = os.environ.get("PYTHONSTARTUP")
- if startup and os.path.isfile(startup):
- with open(startup) as f:
- eval(compile(f.read(), startup, "exec"), ctx)
-
- ctx.update(app.make_shell_context())
-
- # Site, customize, or startup script can set a hook to call when
- # entering interactive mode. The default one sets up readline with
- # tab and history completion.
- interactive_hook = getattr(sys, "__interactivehook__", None)
-
- if interactive_hook is not None:
- try:
- import readline
- from rlcompleter import Completer
- except ImportError:
- pass
- else:
- # rlcompleter uses __main__.__dict__ by default, which is
- # flask.__main__. Use the shell context instead.
- readline.set_completer(Completer(ctx).complete)
-
- interactive_hook()
-
- code.interact(banner=banner, local=ctx)
-
-
-@click.command("routes", short_help="Show the routes for the app.")
-@click.option(
- "--sort",
- "-s",
- type=click.Choice(("endpoint", "methods", "rule", "match")),
- default="endpoint",
- help=(
- 'Method to sort routes by. "match" is the order that Flask will match '
- "routes when dispatching a request."
- ),
-)
-@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.")
-@with_appcontext
-def routes_command(sort: str, all_methods: bool) -> None:
- """Show all registered routes with endpoints and methods."""
-
- rules = list(current_app.url_map.iter_rules())
- if not rules:
- click.echo("No routes were registered.")
- return
-
- ignored_methods = set(() if all_methods else ("HEAD", "OPTIONS"))
-
- if sort in ("endpoint", "rule"):
- rules = sorted(rules, key=attrgetter(sort))
- elif sort == "methods":
- rules = sorted(rules, key=lambda rule: sorted(rule.methods)) # type: ignore
-
- rule_methods = [
- ", ".join(sorted(rule.methods - ignored_methods)) # type: ignore
- for rule in rules
- ]
-
- headers = ("Endpoint", "Methods", "Rule")
- widths = (
- max(len(rule.endpoint) for rule in rules),
- max(len(methods) for methods in rule_methods),
- max(len(rule.rule) for rule in rules),
- )
- widths = [max(len(h), w) for h, w in zip(headers, widths)]
- row = "{{0:<{0}}} {{1:<{1}}} {{2:<{2}}}".format(*widths)
-
- click.echo(row.format(*headers).strip())
- click.echo(row.format(*("-" * width for width in widths)))
-
- for rule, methods in zip(rules, rule_methods):
- click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip())
-
-
-cli = FlaskGroup(
- help="""\
-A general utility script for Flask applications.
-
-Provides commands from Flask, extensions, and the application. Loads the
-application defined in the FLASK_APP environment variable, or from a wsgi.py
-file. Setting the FLASK_ENV environment variable to 'development' will enable
-debug mode.
-
-\b
- {prefix}{cmd} FLASK_APP=hello.py
- {prefix}{cmd} FLASK_ENV=development
- {prefix}flask run
-""".format(
- cmd="export" if os.name == "posix" else "set",
- prefix="$ " if os.name == "posix" else "> ",
- )
-)
-
-
-def main() -> None:
- if int(click.__version__[0]) < 8:
- warnings.warn(
- "Using the `flask` cli with Click 7 is deprecated and"
- " will not be supported starting with Flask 2.1."
- " Please upgrade to Click 8 as soon as possible.",
- DeprecationWarning,
- )
- # TODO omit sys.argv once https://github.com/pallets/click/issues/536 is fixed
- cli.main(args=sys.argv[1:])
-
-
-if __name__ == "__main__":
- main()
diff --git a/venv/lib/python3.9/site-packages/flask/config.py b/venv/lib/python3.9/site-packages/flask/config.py
deleted file mode 100644
index c79a558..0000000
--- a/venv/lib/python3.9/site-packages/flask/config.py
+++ /dev/null
@@ -1,291 +0,0 @@
-import errno
-import os
-import types
-import typing as t
-
-from werkzeug.utils import import_string
-
-
-class ConfigAttribute:
- """Makes an attribute forward to the config"""
-
- def __init__(self, name: str, get_converter: t.Optional[t.Callable] = None) -> None:
- self.__name__ = name
- self.get_converter = get_converter
-
- def __get__(self, obj: t.Any, owner: t.Any = None) -> t.Any:
- if obj is None:
- return self
- rv = obj.config[self.__name__]
- if self.get_converter is not None:
- rv = self.get_converter(rv)
- return rv
-
- def __set__(self, obj: t.Any, value: t.Any) -> None:
- obj.config[self.__name__] = value
-
-
-class Config(dict):
- """Works exactly like a dict but provides ways to fill it from files
- or special dictionaries. There are two common patterns to populate the
- config.
-
- Either you can fill the config from a config file::
-
- app.config.from_pyfile('yourconfig.cfg')
-
- Or alternatively you can define the configuration options in the
- module that calls :meth:`from_object` or provide an import path to
- a module that should be loaded. It is also possible to tell it to
- use the same module and with that provide the configuration values
- just before the call::
-
- DEBUG = True
- SECRET_KEY = 'development key'
- app.config.from_object(__name__)
-
- In both cases (loading from any Python file or loading from modules),
- only uppercase keys are added to the config. This makes it possible to use
- lowercase values in the config file for temporary values that are not added
- to the config or to define the config keys in the same file that implements
- the application.
-
- Probably the most interesting way to load configurations is from an
- environment variable pointing to a file::
-
- app.config.from_envvar('YOURAPPLICATION_SETTINGS')
-
- In this case before launching the application you have to set this
- environment variable to the file you want to use. On Linux and OS X
- use the export statement::
-
- export YOURAPPLICATION_SETTINGS='/path/to/config/file'
-
- On windows use `set` instead.
-
- :param root_path: path to which files are read relative from. When the
- config object is created by the application, this is
- the application's :attr:`~flask.Flask.root_path`.
- :param defaults: an optional dictionary of default values
- """
-
- def __init__(self, root_path: str, defaults: t.Optional[dict] = None) -> None:
- dict.__init__(self, defaults or {})
- self.root_path = root_path
-
- def from_envvar(self, variable_name: str, silent: bool = False) -> bool:
- """Loads a configuration from an environment variable pointing to
- a configuration file. This is basically just a shortcut with nicer
- error messages for this line of code::
-
- app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
-
- :param variable_name: name of the environment variable
- :param silent: set to ``True`` if you want silent failure for missing
- files.
- :return: bool. ``True`` if able to load config, ``False`` otherwise.
- """
- rv = os.environ.get(variable_name)
- if not rv:
- if silent:
- return False
- raise RuntimeError(
- f"The environment variable {variable_name!r} is not set"
- " and as such configuration could not be loaded. Set"
- " this variable and make it point to a configuration"
- " file"
- )
- return self.from_pyfile(rv, silent=silent)
-
- def from_pyfile(self, filename: str, silent: bool = False) -> bool:
- """Updates the values in the config from a Python file. This function
- behaves as if the file was imported as module with the
- :meth:`from_object` function.
-
- :param filename: the filename of the config. This can either be an
- absolute filename or a filename relative to the
- root path.
- :param silent: set to ``True`` if you want silent failure for missing
- files.
-
- .. versionadded:: 0.7
- `silent` parameter.
- """
- filename = os.path.join(self.root_path, filename)
- d = types.ModuleType("config")
- d.__file__ = filename
- try:
- with open(filename, mode="rb") as config_file:
- exec(compile(config_file.read(), filename, "exec"), d.__dict__)
- except OSError as e:
- if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR):
- return False
- e.strerror = f"Unable to load configuration file ({e.strerror})"
- raise
- self.from_object(d)
- return True
-
- def from_object(self, obj: t.Union[object, str]) -> None:
- """Updates the values from the given object. An object can be of one
- of the following two types:
-
- - a string: in this case the object with that name will be imported
- - an actual object reference: that object is used directly
-
- Objects are usually either modules or classes. :meth:`from_object`
- loads only the uppercase attributes of the module/class. A ``dict``
- object will not work with :meth:`from_object` because the keys of a
- ``dict`` are not attributes of the ``dict`` class.
-
- Example of module-based configuration::
-
- app.config.from_object('yourapplication.default_config')
- from yourapplication import default_config
- app.config.from_object(default_config)
-
- Nothing is done to the object before loading. If the object is a
- class and has ``@property`` attributes, it needs to be
- instantiated before being passed to this method.
-
- You should not use this function to load the actual configuration but
- rather configuration defaults. The actual config should be loaded
- with :meth:`from_pyfile` and ideally from a location not within the
- package because the package might be installed system wide.
-
- See :ref:`config-dev-prod` for an example of class-based configuration
- using :meth:`from_object`.
-
- :param obj: an import name or object
- """
- if isinstance(obj, str):
- obj = import_string(obj)
- for key in dir(obj):
- if key.isupper():
- self[key] = getattr(obj, key)
-
- def from_file(
- self,
- filename: str,
- load: t.Callable[[t.IO[t.Any]], t.Mapping],
- silent: bool = False,
- ) -> bool:
- """Update the values in the config from a file that is loaded
- using the ``load`` parameter. The loaded data is passed to the
- :meth:`from_mapping` method.
-
- .. code-block:: python
-
- import toml
- app.config.from_file("config.toml", load=toml.load)
-
- :param filename: The path to the data file. This can be an
- absolute path or relative to the config root path.
- :param load: A callable that takes a file handle and returns a
- mapping of loaded data from the file.
- :type load: ``Callable[[Reader], Mapping]`` where ``Reader``
- implements a ``read`` method.
- :param silent: Ignore the file if it doesn't exist.
-
- .. versionadded:: 2.0
- """
- filename = os.path.join(self.root_path, filename)
-
- try:
- with open(filename) as f:
- obj = load(f)
- except OSError as e:
- if silent and e.errno in (errno.ENOENT, errno.EISDIR):
- return False
-
- e.strerror = f"Unable to load configuration file ({e.strerror})"
- raise
-
- return self.from_mapping(obj)
-
- def from_json(self, filename: str, silent: bool = False) -> bool:
- """Update the values in the config from a JSON file. The loaded
- data is passed to the :meth:`from_mapping` method.
-
- :param filename: The path to the JSON file. This can be an
- absolute path or relative to the config root path.
- :param silent: Ignore the file if it doesn't exist.
-
- .. deprecated:: 2.0.0
- Will be removed in Flask 2.1. Use :meth:`from_file` instead.
- This was removed early in 2.0.0, was added back in 2.0.1.
-
- .. versionadded:: 0.11
- """
- import warnings
- from . import json
-
- warnings.warn(
- "'from_json' is deprecated and will be removed in Flask"
- " 2.1. Use 'from_file(path, json.load)' instead.",
- DeprecationWarning,
- stacklevel=2,
- )
- return self.from_file(filename, json.load, silent=silent)
-
- def from_mapping(
- self, mapping: t.Optional[t.Mapping[str, t.Any]] = None, **kwargs: t.Any
- ) -> bool:
- """Updates the config like :meth:`update` ignoring items with non-upper
- keys.
-
- .. versionadded:: 0.11
- """
- mappings: t.Dict[str, t.Any] = {}
- if mapping is not None:
- mappings.update(mapping)
- mappings.update(kwargs)
- for key, value in mappings.items():
- if key.isupper():
- self[key] = value
- return True
-
- def get_namespace(
- self, namespace: str, lowercase: bool = True, trim_namespace: bool = True
- ) -> t.Dict[str, t.Any]:
- """Returns a dictionary containing a subset of configuration options
- that match the specified namespace/prefix. Example usage::
-
- app.config['IMAGE_STORE_TYPE'] = 'fs'
- app.config['IMAGE_STORE_PATH'] = '/var/app/images'
- app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com'
- image_store_config = app.config.get_namespace('IMAGE_STORE_')
-
- The resulting dictionary `image_store_config` would look like::
-
- {
- 'type': 'fs',
- 'path': '/var/app/images',
- 'base_url': 'http://img.website.com'
- }
-
- This is often useful when configuration options map directly to
- keyword arguments in functions or class constructors.
-
- :param namespace: a configuration namespace
- :param lowercase: a flag indicating if the keys of the resulting
- dictionary should be lowercase
- :param trim_namespace: a flag indicating if the keys of the resulting
- dictionary should not include the namespace
-
- .. versionadded:: 0.11
- """
- rv = {}
- for k, v in self.items():
- if not k.startswith(namespace):
- continue
- if trim_namespace:
- key = k[len(namespace) :]
- else:
- key = k
- if lowercase:
- key = key.lower()
- rv[key] = v
- return rv
-
- def __repr__(self) -> str:
- return f"<{type(self).__name__} {dict.__repr__(self)}>"
diff --git a/venv/lib/python3.9/site-packages/flask/ctx.py b/venv/lib/python3.9/site-packages/flask/ctx.py
deleted file mode 100644
index 5c06463..0000000
--- a/venv/lib/python3.9/site-packages/flask/ctx.py
+++ /dev/null
@@ -1,480 +0,0 @@
-import sys
-import typing as t
-from functools import update_wrapper
-from types import TracebackType
-
-from werkzeug.exceptions import HTTPException
-
-from .globals import _app_ctx_stack
-from .globals import _request_ctx_stack
-from .signals import appcontext_popped
-from .signals import appcontext_pushed
-from .typing import AfterRequestCallable
-
-if t.TYPE_CHECKING:
- from .app import Flask
- from .sessions import SessionMixin
- from .wrappers import Request
-
-
-# a singleton sentinel value for parameter defaults
-_sentinel = object()
-
-
-class _AppCtxGlobals:
- """A plain object. Used as a namespace for storing data during an
- application context.
-
- Creating an app context automatically creates this object, which is
- made available as the :data:`g` proxy.
-
- .. describe:: 'key' in g
-
- Check whether an attribute is present.
-
- .. versionadded:: 0.10
-
- .. describe:: iter(g)
-
- Return an iterator over the attribute names.
-
- .. versionadded:: 0.10
- """
-
- # Define attr methods to let mypy know this is a namespace object
- # that has arbitrary attributes.
-
- def __getattr__(self, name: str) -> t.Any:
- try:
- return self.__dict__[name]
- except KeyError:
- raise AttributeError(name) from None
-
- def __setattr__(self, name: str, value: t.Any) -> None:
- self.__dict__[name] = value
-
- def __delattr__(self, name: str) -> None:
- try:
- del self.__dict__[name]
- except KeyError:
- raise AttributeError(name) from None
-
- def get(self, name: str, default: t.Optional[t.Any] = None) -> t.Any:
- """Get an attribute by name, or a default value. Like
- :meth:`dict.get`.
-
- :param name: Name of attribute to get.
- :param default: Value to return if the attribute is not present.
-
- .. versionadded:: 0.10
- """
- return self.__dict__.get(name, default)
-
- def pop(self, name: str, default: t.Any = _sentinel) -> t.Any:
- """Get and remove an attribute by name. Like :meth:`dict.pop`.
-
- :param name: Name of attribute to pop.
- :param default: Value to return if the attribute is not present,
- instead of raising a ``KeyError``.
-
- .. versionadded:: 0.11
- """
- if default is _sentinel:
- return self.__dict__.pop(name)
- else:
- return self.__dict__.pop(name, default)
-
- def setdefault(self, name: str, default: t.Any = None) -> t.Any:
- """Get the value of an attribute if it is present, otherwise
- set and return a default value. Like :meth:`dict.setdefault`.
-
- :param name: Name of attribute to get.
- :param default: Value to set and return if the attribute is not
- present.
-
- .. versionadded:: 0.11
- """
- return self.__dict__.setdefault(name, default)
-
- def __contains__(self, item: str) -> bool:
- return item in self.__dict__
-
- def __iter__(self) -> t.Iterator[str]:
- return iter(self.__dict__)
-
- def __repr__(self) -> str:
- top = _app_ctx_stack.top
- if top is not None:
- return f""
- return object.__repr__(self)
-
-
-def after_this_request(f: AfterRequestCallable) -> AfterRequestCallable:
- """Executes a function after this request. This is useful to modify
- response objects. The function is passed the response object and has
- to return the same or a new one.
-
- Example::
-
- @app.route('/')
- def index():
- @after_this_request
- def add_header(response):
- response.headers['X-Foo'] = 'Parachute'
- return response
- return 'Hello World!'
-
- This is more useful if a function other than the view function wants to
- modify a response. For instance think of a decorator that wants to add
- some headers without converting the return value into a response object.
-
- .. versionadded:: 0.9
- """
- _request_ctx_stack.top._after_request_functions.append(f)
- return f
-
-
-def copy_current_request_context(f: t.Callable) -> t.Callable:
- """A helper function that decorates a function to retain the current
- request context. This is useful when working with greenlets. The moment
- the function is decorated a copy of the request context is created and
- then pushed when the function is called. The current session is also
- included in the copied request context.
-
- Example::
-
- import gevent
- from flask import copy_current_request_context
-
- @app.route('/')
- def index():
- @copy_current_request_context
- def do_some_work():
- # do some work here, it can access flask.request or
- # flask.session like you would otherwise in the view function.
- ...
- gevent.spawn(do_some_work)
- return 'Regular response'
-
- .. versionadded:: 0.10
- """
- top = _request_ctx_stack.top
- if top is None:
- raise RuntimeError(
- "This decorator can only be used at local scopes "
- "when a request context is on the stack. For instance within "
- "view functions."
- )
- reqctx = top.copy()
-
- def wrapper(*args, **kwargs):
- with reqctx:
- return f(*args, **kwargs)
-
- return update_wrapper(wrapper, f)
-
-
-def has_request_context() -> bool:
- """If you have code that wants to test if a request context is there or
- not this function can be used. For instance, you may want to take advantage
- of request information if the request object is available, but fail
- silently if it is unavailable.
-
- ::
-
- class User(db.Model):
-
- def __init__(self, username, remote_addr=None):
- self.username = username
- if remote_addr is None and has_request_context():
- remote_addr = request.remote_addr
- self.remote_addr = remote_addr
-
- Alternatively you can also just test any of the context bound objects
- (such as :class:`request` or :class:`g`) for truthness::
-
- class User(db.Model):
-
- def __init__(self, username, remote_addr=None):
- self.username = username
- if remote_addr is None and request:
- remote_addr = request.remote_addr
- self.remote_addr = remote_addr
-
- .. versionadded:: 0.7
- """
- return _request_ctx_stack.top is not None
-
-
-def has_app_context() -> bool:
- """Works like :func:`has_request_context` but for the application
- context. You can also just do a boolean check on the
- :data:`current_app` object instead.
-
- .. versionadded:: 0.9
- """
- return _app_ctx_stack.top is not None
-
-
-class AppContext:
- """The application context binds an application object implicitly
- to the current thread or greenlet, similar to how the
- :class:`RequestContext` binds request information. The application
- context is also implicitly created if a request context is created
- but the application is not on top of the individual application
- context.
- """
-
- def __init__(self, app: "Flask") -> None:
- self.app = app
- self.url_adapter = app.create_url_adapter(None)
- self.g = app.app_ctx_globals_class()
-
- # Like request context, app contexts can be pushed multiple times
- # but there a basic "refcount" is enough to track them.
- self._refcnt = 0
-
- def push(self) -> None:
- """Binds the app context to the current context."""
- self._refcnt += 1
- _app_ctx_stack.push(self)
- appcontext_pushed.send(self.app)
-
- def pop(self, exc: t.Optional[BaseException] = _sentinel) -> None: # type: ignore
- """Pops the app context."""
- try:
- self._refcnt -= 1
- if self._refcnt <= 0:
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- self.app.do_teardown_appcontext(exc)
- finally:
- rv = _app_ctx_stack.pop()
- assert rv is self, f"Popped wrong app context. ({rv!r} instead of {self!r})"
- appcontext_popped.send(self.app)
-
- def __enter__(self) -> "AppContext":
- self.push()
- return self
-
- def __exit__(
- self, exc_type: type, exc_value: BaseException, tb: TracebackType
- ) -> None:
- self.pop(exc_value)
-
-
-class RequestContext:
- """The request context contains all request relevant information. It is
- created at the beginning of the request and pushed to the
- `_request_ctx_stack` and removed at the end of it. It will create the
- URL adapter and request object for the WSGI environment provided.
-
- Do not attempt to use this class directly, instead use
- :meth:`~flask.Flask.test_request_context` and
- :meth:`~flask.Flask.request_context` to create this object.
-
- When the request context is popped, it will evaluate all the
- functions registered on the application for teardown execution
- (:meth:`~flask.Flask.teardown_request`).
-
- The request context is automatically popped at the end of the request
- for you. In debug mode the request context is kept around if
- exceptions happen so that interactive debuggers have a chance to
- introspect the data. With 0.4 this can also be forced for requests
- that did not fail and outside of ``DEBUG`` mode. By setting
- ``'flask._preserve_context'`` to ``True`` on the WSGI environment the
- context will not pop itself at the end of the request. This is used by
- the :meth:`~flask.Flask.test_client` for example to implement the
- deferred cleanup functionality.
-
- You might find this helpful for unittests where you need the
- information from the context local around for a little longer. Make
- sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in
- that situation, otherwise your unittests will leak memory.
- """
-
- def __init__(
- self,
- app: "Flask",
- environ: dict,
- request: t.Optional["Request"] = None,
- session: t.Optional["SessionMixin"] = None,
- ) -> None:
- self.app = app
- if request is None:
- request = app.request_class(environ)
- self.request = request
- self.url_adapter = None
- try:
- self.url_adapter = app.create_url_adapter(self.request)
- except HTTPException as e:
- self.request.routing_exception = e
- self.flashes = None
- self.session = session
-
- # Request contexts can be pushed multiple times and interleaved with
- # other request contexts. Now only if the last level is popped we
- # get rid of them. Additionally if an application context is missing
- # one is created implicitly so for each level we add this information
- self._implicit_app_ctx_stack: t.List[t.Optional["AppContext"]] = []
-
- # indicator if the context was preserved. Next time another context
- # is pushed the preserved context is popped.
- self.preserved = False
-
- # remembers the exception for pop if there is one in case the context
- # preservation kicks in.
- self._preserved_exc = None
-
- # Functions that should be executed after the request on the response
- # object. These will be called before the regular "after_request"
- # functions.
- self._after_request_functions: t.List[AfterRequestCallable] = []
-
- @property
- def g(self) -> AppContext:
- return _app_ctx_stack.top.g
-
- @g.setter
- def g(self, value: AppContext) -> None:
- _app_ctx_stack.top.g = value
-
- def copy(self) -> "RequestContext":
- """Creates a copy of this request context with the same request object.
- This can be used to move a request context to a different greenlet.
- Because the actual request object is the same this cannot be used to
- move a request context to a different thread unless access to the
- request object is locked.
-
- .. versionadded:: 0.10
-
- .. versionchanged:: 1.1
- The current session object is used instead of reloading the original
- data. This prevents `flask.session` pointing to an out-of-date object.
- """
- return self.__class__(
- self.app,
- environ=self.request.environ,
- request=self.request,
- session=self.session,
- )
-
- def match_request(self) -> None:
- """Can be overridden by a subclass to hook into the matching
- of the request.
- """
- try:
- result = self.url_adapter.match(return_rule=True) # type: ignore
- self.request.url_rule, self.request.view_args = result # type: ignore
- except HTTPException as e:
- self.request.routing_exception = e
-
- def push(self) -> None:
- """Binds the request context to the current context."""
- # If an exception occurs in debug mode or if context preservation is
- # activated under exception situations exactly one context stays
- # on the stack. The rationale is that you want to access that
- # information under debug situations. However if someone forgets to
- # pop that context again we want to make sure that on the next push
- # it's invalidated, otherwise we run at risk that something leaks
- # memory. This is usually only a problem in test suite since this
- # functionality is not active in production environments.
- top = _request_ctx_stack.top
- if top is not None and top.preserved:
- top.pop(top._preserved_exc)
-
- # Before we push the request context we have to ensure that there
- # is an application context.
- app_ctx = _app_ctx_stack.top
- if app_ctx is None or app_ctx.app != self.app:
- app_ctx = self.app.app_context()
- app_ctx.push()
- self._implicit_app_ctx_stack.append(app_ctx)
- else:
- self._implicit_app_ctx_stack.append(None)
-
- _request_ctx_stack.push(self)
-
- # Open the session at the moment that the request context is available.
- # This allows a custom open_session method to use the request context.
- # Only open a new session if this is the first time the request was
- # pushed, otherwise stream_with_context loses the session.
- if self.session is None:
- session_interface = self.app.session_interface
- self.session = session_interface.open_session(self.app, self.request)
-
- if self.session is None:
- self.session = session_interface.make_null_session(self.app)
-
- # Match the request URL after loading the session, so that the
- # session is available in custom URL converters.
- if self.url_adapter is not None:
- self.match_request()
-
- def pop(self, exc: t.Optional[BaseException] = _sentinel) -> None: # type: ignore
- """Pops the request context and unbinds it by doing that. This will
- also trigger the execution of functions registered by the
- :meth:`~flask.Flask.teardown_request` decorator.
-
- .. versionchanged:: 0.9
- Added the `exc` argument.
- """
- app_ctx = self._implicit_app_ctx_stack.pop()
- clear_request = False
-
- try:
- if not self._implicit_app_ctx_stack:
- self.preserved = False
- self._preserved_exc = None
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- self.app.do_teardown_request(exc)
-
- request_close = getattr(self.request, "close", None)
- if request_close is not None:
- request_close()
- clear_request = True
- finally:
- rv = _request_ctx_stack.pop()
-
- # get rid of circular dependencies at the end of the request
- # so that we don't require the GC to be active.
- if clear_request:
- rv.request.environ["werkzeug.request"] = None
-
- # Get rid of the app as well if necessary.
- if app_ctx is not None:
- app_ctx.pop(exc)
-
- assert (
- rv is self
- ), f"Popped wrong request context. ({rv!r} instead of {self!r})"
-
- def auto_pop(self, exc: t.Optional[BaseException]) -> None:
- if self.request.environ.get("flask._preserve_context") or (
- exc is not None and self.app.preserve_context_on_exception
- ):
- self.preserved = True
- self._preserved_exc = exc # type: ignore
- else:
- self.pop(exc)
-
- def __enter__(self) -> "RequestContext":
- self.push()
- return self
-
- def __exit__(
- self, exc_type: type, exc_value: BaseException, tb: TracebackType
- ) -> None:
- # do not pop the request stack if we are in debug mode and an
- # exception happened. This will allow the debugger to still
- # access the request object in the interactive shell. Furthermore
- # the context can be force kept alive for the test client.
- # See flask.testing for how this works.
- self.auto_pop(exc_value)
-
- def __repr__(self) -> str:
- return (
- f"<{type(self).__name__} {self.request.url!r}"
- f" [{self.request.method}] of {self.app.name}>"
- )
diff --git a/venv/lib/python3.9/site-packages/flask/debughelpers.py b/venv/lib/python3.9/site-packages/flask/debughelpers.py
deleted file mode 100644
index ce65c48..0000000
--- a/venv/lib/python3.9/site-packages/flask/debughelpers.py
+++ /dev/null
@@ -1,171 +0,0 @@
-import os
-import typing as t
-from warnings import warn
-
-from .app import Flask
-from .blueprints import Blueprint
-from .globals import _request_ctx_stack
-
-
-class UnexpectedUnicodeError(AssertionError, UnicodeError):
- """Raised in places where we want some better error reporting for
- unexpected unicode or binary data.
- """
-
-
-class DebugFilesKeyError(KeyError, AssertionError):
- """Raised from request.files during debugging. The idea is that it can
- provide a better error message than just a generic KeyError/BadRequest.
- """
-
- def __init__(self, request, key):
- form_matches = request.form.getlist(key)
- buf = [
- f"You tried to access the file {key!r} in the request.files"
- " dictionary but it does not exist. The mimetype for the"
- f" request is {request.mimetype!r} instead of"
- " 'multipart/form-data' which means that no file contents"
- " were transmitted. To fix this error you should provide"
- ' enctype="multipart/form-data" in your form.'
- ]
- if form_matches:
- names = ", ".join(repr(x) for x in form_matches)
- buf.append(
- "\n\nThe browser instead transmitted some file names. "
- f"This was submitted: {names}"
- )
- self.msg = "".join(buf)
-
- def __str__(self):
- return self.msg
-
-
-class FormDataRoutingRedirect(AssertionError):
- """This exception is raised by Flask in debug mode if it detects a
- redirect caused by the routing system when the request method is not
- GET, HEAD or OPTIONS. Reasoning: form data will be dropped.
- """
-
- def __init__(self, request):
- exc = request.routing_exception
- buf = [
- f"A request was sent to this URL ({request.url}) but a"
- " redirect was issued automatically by the routing system"
- f" to {exc.new_url!r}."
- ]
-
- # In case just a slash was appended we can be extra helpful
- if f"{request.base_url}/" == exc.new_url.split("?")[0]:
- buf.append(
- " The URL was defined with a trailing slash so Flask"
- " will automatically redirect to the URL with the"
- " trailing slash if it was accessed without one."
- )
-
- buf.append(
- " Make sure to directly send your"
- f" {request.method}-request to this URL since we can't make"
- " browsers or HTTP clients redirect with form data reliably"
- " or without user interaction."
- )
- buf.append("\n\nNote: this exception is only raised in debug mode")
- AssertionError.__init__(self, "".join(buf).encode("utf-8"))
-
-
-def attach_enctype_error_multidict(request):
- """Since Flask 0.8 we're monkeypatching the files object in case a
- request is detected that does not use multipart form data but the files
- object is accessed.
- """
- oldcls = request.files.__class__
-
- class newcls(oldcls):
- def __getitem__(self, key):
- try:
- return oldcls.__getitem__(self, key)
- except KeyError:
- if key not in request.form:
- raise
- raise DebugFilesKeyError(request, key)
-
- newcls.__name__ = oldcls.__name__
- newcls.__module__ = oldcls.__module__
- request.files.__class__ = newcls
-
-
-def _dump_loader_info(loader) -> t.Generator:
- yield f"class: {type(loader).__module__}.{type(loader).__name__}"
- for key, value in sorted(loader.__dict__.items()):
- if key.startswith("_"):
- continue
- if isinstance(value, (tuple, list)):
- if not all(isinstance(x, str) for x in value):
- continue
- yield f"{key}:"
- for item in value:
- yield f" - {item}"
- continue
- elif not isinstance(value, (str, int, float, bool)):
- continue
- yield f"{key}: {value!r}"
-
-
-def explain_template_loading_attempts(app: Flask, template, attempts) -> None:
- """This should help developers understand what failed"""
- info = [f"Locating template {template!r}:"]
- total_found = 0
- blueprint = None
- reqctx = _request_ctx_stack.top
- if reqctx is not None and reqctx.request.blueprint is not None:
- blueprint = reqctx.request.blueprint
-
- for idx, (loader, srcobj, triple) in enumerate(attempts):
- if isinstance(srcobj, Flask):
- src_info = f"application {srcobj.import_name!r}"
- elif isinstance(srcobj, Blueprint):
- src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})"
- else:
- src_info = repr(srcobj)
-
- info.append(f"{idx + 1:5}: trying loader of {src_info}")
-
- for line in _dump_loader_info(loader):
- info.append(f" {line}")
-
- if triple is None:
- detail = "no match"
- else:
- detail = f"found ({triple[1] or ''!r})"
- total_found += 1
- info.append(f" -> {detail}")
-
- seems_fishy = False
- if total_found == 0:
- info.append("Error: the template could not be found.")
- seems_fishy = True
- elif total_found > 1:
- info.append("Warning: multiple loaders returned a match for the template.")
- seems_fishy = True
-
- if blueprint is not None and seems_fishy:
- info.append(
- " The template was looked up from an endpoint that belongs"
- f" to the blueprint {blueprint!r}."
- )
- info.append(" Maybe you did not place a template in the right folder?")
- info.append(" See https://flask.palletsprojects.com/blueprints/#templates")
-
- app.logger.info("\n".join(info))
-
-
-def explain_ignored_app_run() -> None:
- if os.environ.get("WERKZEUG_RUN_MAIN") != "true":
- warn(
- Warning(
- "Silently ignoring app.run() because the application is"
- " run from the flask command line executable. Consider"
- ' putting app.run() behind an if __name__ == "__main__"'
- " guard to silence this warning."
- ),
- stacklevel=3,
- )
diff --git a/venv/lib/python3.9/site-packages/flask/globals.py b/venv/lib/python3.9/site-packages/flask/globals.py
deleted file mode 100644
index 6d91c75..0000000
--- a/venv/lib/python3.9/site-packages/flask/globals.py
+++ /dev/null
@@ -1,59 +0,0 @@
-import typing as t
-from functools import partial
-
-from werkzeug.local import LocalProxy
-from werkzeug.local import LocalStack
-
-if t.TYPE_CHECKING:
- from .app import Flask
- from .ctx import _AppCtxGlobals
- from .sessions import SessionMixin
- from .wrappers import Request
-
-_request_ctx_err_msg = """\
-Working outside of request context.
-
-This typically means that you attempted to use functionality that needed
-an active HTTP request. Consult the documentation on testing for
-information about how to avoid this problem.\
-"""
-_app_ctx_err_msg = """\
-Working outside of application context.
-
-This typically means that you attempted to use functionality that needed
-to interface with the current application object in some way. To solve
-this, set up an application context with app.app_context(). See the
-documentation for more information.\
-"""
-
-
-def _lookup_req_object(name):
- top = _request_ctx_stack.top
- if top is None:
- raise RuntimeError(_request_ctx_err_msg)
- return getattr(top, name)
-
-
-def _lookup_app_object(name):
- top = _app_ctx_stack.top
- if top is None:
- raise RuntimeError(_app_ctx_err_msg)
- return getattr(top, name)
-
-
-def _find_app():
- top = _app_ctx_stack.top
- if top is None:
- raise RuntimeError(_app_ctx_err_msg)
- return top.app
-
-
-# context locals
-_request_ctx_stack = LocalStack()
-_app_ctx_stack = LocalStack()
-current_app: "Flask" = LocalProxy(_find_app) # type: ignore
-request: "Request" = LocalProxy(partial(_lookup_req_object, "request")) # type: ignore
-session: "SessionMixin" = LocalProxy( # type: ignore
- partial(_lookup_req_object, "session")
-)
-g: "_AppCtxGlobals" = LocalProxy(partial(_lookup_app_object, "g")) # type: ignore
diff --git a/venv/lib/python3.9/site-packages/flask/helpers.py b/venv/lib/python3.9/site-packages/flask/helpers.py
deleted file mode 100644
index 7b8b087..0000000
--- a/venv/lib/python3.9/site-packages/flask/helpers.py
+++ /dev/null
@@ -1,836 +0,0 @@
-import os
-import pkgutil
-import socket
-import sys
-import typing as t
-import warnings
-from datetime import datetime
-from datetime import timedelta
-from functools import lru_cache
-from functools import update_wrapper
-from threading import RLock
-
-import werkzeug.utils
-from werkzeug.exceptions import NotFound
-from werkzeug.routing import BuildError
-from werkzeug.urls import url_quote
-
-from .globals import _app_ctx_stack
-from .globals import _request_ctx_stack
-from .globals import current_app
-from .globals import request
-from .globals import session
-from .signals import message_flashed
-
-if t.TYPE_CHECKING:
- from .wrappers import Response
-
-
-def get_env() -> str:
- """Get the environment the app is running in, indicated by the
- :envvar:`FLASK_ENV` environment variable. The default is
- ``'production'``.
- """
- return os.environ.get("FLASK_ENV") or "production"
-
-
-def get_debug_flag() -> bool:
- """Get whether debug mode should be enabled for the app, indicated
- by the :envvar:`FLASK_DEBUG` environment variable. The default is
- ``True`` if :func:`.get_env` returns ``'development'``, or ``False``
- otherwise.
- """
- val = os.environ.get("FLASK_DEBUG")
-
- if not val:
- return get_env() == "development"
-
- return val.lower() not in ("0", "false", "no")
-
-
-def get_load_dotenv(default: bool = True) -> bool:
- """Get whether the user has disabled loading dotenv files by setting
- :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load the
- files.
-
- :param default: What to return if the env var isn't set.
- """
- val = os.environ.get("FLASK_SKIP_DOTENV")
-
- if not val:
- return default
-
- return val.lower() in ("0", "false", "no")
-
-
-def stream_with_context(
- generator_or_function: t.Union[
- t.Iterator[t.AnyStr], t.Callable[..., t.Iterator[t.AnyStr]]
- ]
-) -> t.Iterator[t.AnyStr]:
- """Request contexts disappear when the response is started on the server.
- This is done for efficiency reasons and to make it less likely to encounter
- memory leaks with badly written WSGI middlewares. The downside is that if
- you are using streamed responses, the generator cannot access request bound
- information any more.
-
- This function however can help you keep the context around for longer::
-
- from flask import stream_with_context, request, Response
-
- @app.route('/stream')
- def streamed_response():
- @stream_with_context
- def generate():
- yield 'Hello '
- yield request.args['name']
- yield '!'
- return Response(generate())
-
- Alternatively it can also be used around a specific generator::
-
- from flask import stream_with_context, request, Response
-
- @app.route('/stream')
- def streamed_response():
- def generate():
- yield 'Hello '
- yield request.args['name']
- yield '!'
- return Response(stream_with_context(generate()))
-
- .. versionadded:: 0.9
- """
- try:
- gen = iter(generator_or_function) # type: ignore
- except TypeError:
-
- def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any:
- gen = generator_or_function(*args, **kwargs) # type: ignore
- return stream_with_context(gen)
-
- return update_wrapper(decorator, generator_or_function) # type: ignore
-
- def generator() -> t.Generator:
- ctx = _request_ctx_stack.top
- if ctx is None:
- raise RuntimeError(
- "Attempted to stream with context but "
- "there was no context in the first place to keep around."
- )
- with ctx:
- # Dummy sentinel. Has to be inside the context block or we're
- # not actually keeping the context around.
- yield None
-
- # The try/finally is here so that if someone passes a WSGI level
- # iterator in we're still running the cleanup logic. Generators
- # don't need that because they are closed on their destruction
- # automatically.
- try:
- yield from gen
- finally:
- if hasattr(gen, "close"):
- gen.close() # type: ignore
-
- # The trick is to start the generator. Then the code execution runs until
- # the first dummy None is yielded at which point the context was already
- # pushed. This item is discarded. Then when the iteration continues the
- # real generator is executed.
- wrapped_g = generator()
- next(wrapped_g)
- return wrapped_g
-
-
-def make_response(*args: t.Any) -> "Response":
- """Sometimes it is necessary to set additional headers in a view. Because
- views do not have to return response objects but can return a value that
- is converted into a response object by Flask itself, it becomes tricky to
- add headers to it. This function can be called instead of using a return
- and you will get a response object which you can use to attach headers.
-
- If view looked like this and you want to add a new header::
-
- def index():
- return render_template('index.html', foo=42)
-
- You can now do something like this::
-
- def index():
- response = make_response(render_template('index.html', foo=42))
- response.headers['X-Parachutes'] = 'parachutes are cool'
- return response
-
- This function accepts the very same arguments you can return from a
- view function. This for example creates a response with a 404 error
- code::
-
- response = make_response(render_template('not_found.html'), 404)
-
- The other use case of this function is to force the return value of a
- view function into a response which is helpful with view
- decorators::
-
- response = make_response(view_function())
- response.headers['X-Parachutes'] = 'parachutes are cool'
-
- Internally this function does the following things:
-
- - if no arguments are passed, it creates a new response argument
- - if one argument is passed, :meth:`flask.Flask.make_response`
- is invoked with it.
- - if more than one argument is passed, the arguments are passed
- to the :meth:`flask.Flask.make_response` function as tuple.
-
- .. versionadded:: 0.6
- """
- if not args:
- return current_app.response_class()
- if len(args) == 1:
- args = args[0]
- return current_app.make_response(args)
-
-
-def url_for(endpoint: str, **values: t.Any) -> str:
- """Generates a URL to the given endpoint with the method provided.
-
- Variable arguments that are unknown to the target endpoint are appended
- to the generated URL as query arguments. If the value of a query argument
- is ``None``, the whole pair is skipped. In case blueprints are active
- you can shortcut references to the same blueprint by prefixing the
- local endpoint with a dot (``.``).
-
- This will reference the index function local to the current blueprint::
-
- url_for('.index')
-
- See :ref:`url-building`.
-
- Configuration values ``APPLICATION_ROOT`` and ``SERVER_NAME`` are only used when
- generating URLs outside of a request context.
-
- To integrate applications, :class:`Flask` has a hook to intercept URL build
- errors through :attr:`Flask.url_build_error_handlers`. The `url_for`
- function results in a :exc:`~werkzeug.routing.BuildError` when the current
- app does not have a URL for the given endpoint and values. When it does, the
- :data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if
- it is not ``None``, which can return a string to use as the result of
- `url_for` (instead of `url_for`'s default to raise the
- :exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception.
- An example::
-
- def external_url_handler(error, endpoint, values):
- "Looks up an external URL when `url_for` cannot build a URL."
- # This is an example of hooking the build_error_handler.
- # Here, lookup_url is some utility function you've built
- # which looks up the endpoint in some external URL registry.
- url = lookup_url(endpoint, **values)
- if url is None:
- # External lookup did not have a URL.
- # Re-raise the BuildError, in context of original traceback.
- exc_type, exc_value, tb = sys.exc_info()
- if exc_value is error:
- raise exc_type(exc_value).with_traceback(tb)
- else:
- raise error
- # url_for will use this result, instead of raising BuildError.
- return url
-
- app.url_build_error_handlers.append(external_url_handler)
-
- Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and
- `endpoint` and `values` are the arguments passed into `url_for`. Note
- that this is for building URLs outside the current application, and not for
- handling 404 NotFound errors.
-
- .. versionadded:: 0.10
- The `_scheme` parameter was added.
-
- .. versionadded:: 0.9
- The `_anchor` and `_method` parameters were added.
-
- .. versionadded:: 0.9
- Calls :meth:`Flask.handle_build_error` on
- :exc:`~werkzeug.routing.BuildError`.
-
- :param endpoint: the endpoint of the URL (name of the function)
- :param values: the variable arguments of the URL rule
- :param _external: if set to ``True``, an absolute URL is generated. Server
- address can be changed via ``SERVER_NAME`` configuration variable which
- falls back to the `Host` header, then to the IP and port of the request.
- :param _scheme: a string specifying the desired URL scheme. The `_external`
- parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default
- behavior uses the same scheme as the current request, or
- :data:`PREFERRED_URL_SCHEME` if no request context is available.
- This also can be set to an empty string to build protocol-relative
- URLs.
- :param _anchor: if provided this is added as anchor to the URL.
- :param _method: if provided this explicitly specifies an HTTP method.
- """
- appctx = _app_ctx_stack.top
- reqctx = _request_ctx_stack.top
-
- if appctx is None:
- raise RuntimeError(
- "Attempted to generate a URL without the application context being"
- " pushed. This has to be executed when application context is"
- " available."
- )
-
- # If request specific information is available we have some extra
- # features that support "relative" URLs.
- if reqctx is not None:
- url_adapter = reqctx.url_adapter
- blueprint_name = request.blueprint
-
- if endpoint[:1] == ".":
- if blueprint_name is not None:
- endpoint = f"{blueprint_name}{endpoint}"
- else:
- endpoint = endpoint[1:]
-
- external = values.pop("_external", False)
-
- # Otherwise go with the url adapter from the appctx and make
- # the URLs external by default.
- else:
- url_adapter = appctx.url_adapter
-
- if url_adapter is None:
- raise RuntimeError(
- "Application was not able to create a URL adapter for request"
- " independent URL generation. You might be able to fix this by"
- " setting the SERVER_NAME config variable."
- )
-
- external = values.pop("_external", True)
-
- anchor = values.pop("_anchor", None)
- method = values.pop("_method", None)
- scheme = values.pop("_scheme", None)
- appctx.app.inject_url_defaults(endpoint, values)
-
- # This is not the best way to deal with this but currently the
- # underlying Werkzeug router does not support overriding the scheme on
- # a per build call basis.
- old_scheme = None
- if scheme is not None:
- if not external:
- raise ValueError("When specifying _scheme, _external must be True")
- old_scheme = url_adapter.url_scheme
- url_adapter.url_scheme = scheme
-
- try:
- try:
- rv = url_adapter.build(
- endpoint, values, method=method, force_external=external
- )
- finally:
- if old_scheme is not None:
- url_adapter.url_scheme = old_scheme
- except BuildError as error:
- # We need to inject the values again so that the app callback can
- # deal with that sort of stuff.
- values["_external"] = external
- values["_anchor"] = anchor
- values["_method"] = method
- values["_scheme"] = scheme
- return appctx.app.handle_url_build_error(error, endpoint, values)
-
- if anchor is not None:
- rv += f"#{url_quote(anchor)}"
- return rv
-
-
-def get_template_attribute(template_name: str, attribute: str) -> t.Any:
- """Loads a macro (or variable) a template exports. This can be used to
- invoke a macro from within Python code. If you for example have a
- template named :file:`_cider.html` with the following contents:
-
- .. sourcecode:: html+jinja
-
- {% macro hello(name) %}Hello {{ name }}!{% endmacro %}
-
- You can access this from Python code like this::
-
- hello = get_template_attribute('_cider.html', 'hello')
- return hello('World')
-
- .. versionadded:: 0.2
-
- :param template_name: the name of the template
- :param attribute: the name of the variable of macro to access
- """
- return getattr(current_app.jinja_env.get_template(template_name).module, attribute)
-
-
-def flash(message: str, category: str = "message") -> None:
- """Flashes a message to the next request. In order to remove the
- flashed message from the session and to display it to the user,
- the template has to call :func:`get_flashed_messages`.
-
- .. versionchanged:: 0.3
- `category` parameter added.
-
- :param message: the message to be flashed.
- :param category: the category for the message. The following values
- are recommended: ``'message'`` for any kind of message,
- ``'error'`` for errors, ``'info'`` for information
- messages and ``'warning'`` for warnings. However any
- kind of string can be used as category.
- """
- # Original implementation:
- #
- # session.setdefault('_flashes', []).append((category, message))
- #
- # This assumed that changes made to mutable structures in the session are
- # always in sync with the session object, which is not true for session
- # implementations that use external storage for keeping their keys/values.
- flashes = session.get("_flashes", [])
- flashes.append((category, message))
- session["_flashes"] = flashes
- message_flashed.send(
- current_app._get_current_object(), # type: ignore
- message=message,
- category=category,
- )
-
-
-def get_flashed_messages(
- with_categories: bool = False, category_filter: t.Iterable[str] = ()
-) -> t.Union[t.List[str], t.List[t.Tuple[str, str]]]:
- """Pulls all flashed messages from the session and returns them.
- Further calls in the same request to the function will return
- the same messages. By default just the messages are returned,
- but when `with_categories` is set to ``True``, the return value will
- be a list of tuples in the form ``(category, message)`` instead.
-
- Filter the flashed messages to one or more categories by providing those
- categories in `category_filter`. This allows rendering categories in
- separate html blocks. The `with_categories` and `category_filter`
- arguments are distinct:
-
- * `with_categories` controls whether categories are returned with message
- text (``True`` gives a tuple, where ``False`` gives just the message text).
- * `category_filter` filters the messages down to only those matching the
- provided categories.
-
- See :doc:`/patterns/flashing` for examples.
-
- .. versionchanged:: 0.3
- `with_categories` parameter added.
-
- .. versionchanged:: 0.9
- `category_filter` parameter added.
-
- :param with_categories: set to ``True`` to also receive categories.
- :param category_filter: filter of categories to limit return values. Only
- categories in the list will be returned.
- """
- flashes = _request_ctx_stack.top.flashes
- if flashes is None:
- _request_ctx_stack.top.flashes = flashes = (
- session.pop("_flashes") if "_flashes" in session else []
- )
- if category_filter:
- flashes = list(filter(lambda f: f[0] in category_filter, flashes))
- if not with_categories:
- return [x[1] for x in flashes]
- return flashes
-
-
-def _prepare_send_file_kwargs(
- download_name: t.Optional[str] = None,
- attachment_filename: t.Optional[str] = None,
- etag: t.Optional[t.Union[bool, str]] = None,
- add_etags: t.Optional[t.Union[bool]] = None,
- max_age: t.Optional[
- t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]]
- ] = None,
- cache_timeout: t.Optional[int] = None,
- **kwargs: t.Any,
-) -> t.Dict[str, t.Any]:
- if attachment_filename is not None:
- warnings.warn(
- "The 'attachment_filename' parameter has been renamed to"
- " 'download_name'. The old name will be removed in Flask"
- " 2.1.",
- DeprecationWarning,
- stacklevel=3,
- )
- download_name = attachment_filename
-
- if cache_timeout is not None:
- warnings.warn(
- "The 'cache_timeout' parameter has been renamed to"
- " 'max_age'. The old name will be removed in Flask 2.1.",
- DeprecationWarning,
- stacklevel=3,
- )
- max_age = cache_timeout
-
- if add_etags is not None:
- warnings.warn(
- "The 'add_etags' parameter has been renamed to 'etag'. The"
- " old name will be removed in Flask 2.1.",
- DeprecationWarning,
- stacklevel=3,
- )
- etag = add_etags
-
- if max_age is None:
- max_age = current_app.get_send_file_max_age
-
- kwargs.update(
- environ=request.environ,
- download_name=download_name,
- etag=etag,
- max_age=max_age,
- use_x_sendfile=current_app.use_x_sendfile,
- response_class=current_app.response_class,
- _root_path=current_app.root_path, # type: ignore
- )
- return kwargs
-
-
-def send_file(
- path_or_file: t.Union[os.PathLike, str, t.BinaryIO],
- mimetype: t.Optional[str] = None,
- as_attachment: bool = False,
- download_name: t.Optional[str] = None,
- attachment_filename: t.Optional[str] = None,
- conditional: bool = True,
- etag: t.Union[bool, str] = True,
- add_etags: t.Optional[bool] = None,
- last_modified: t.Optional[t.Union[datetime, int, float]] = None,
- max_age: t.Optional[
- t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]]
- ] = None,
- cache_timeout: t.Optional[int] = None,
-):
- """Send the contents of a file to the client.
-
- The first argument can be a file path or a file-like object. Paths
- are preferred in most cases because Werkzeug can manage the file and
- get extra information from the path. Passing a file-like object
- requires that the file is opened in binary mode, and is mostly
- useful when building a file in memory with :class:`io.BytesIO`.
-
- Never pass file paths provided by a user. The path is assumed to be
- trusted, so a user could craft a path to access a file you didn't
- intend. Use :func:`send_from_directory` to safely serve
- user-requested paths from within a directory.
-
- If the WSGI server sets a ``file_wrapper`` in ``environ``, it is
- used, otherwise Werkzeug's built-in wrapper is used. Alternatively,
- if the HTTP server supports ``X-Sendfile``, configuring Flask with
- ``USE_X_SENDFILE = True`` will tell the server to send the given
- path, which is much more efficient than reading it in Python.
-
- :param path_or_file: The path to the file to send, relative to the
- current working directory if a relative path is given.
- Alternatively, a file-like object opened in binary mode. Make
- sure the file pointer is seeked to the start of the data.
- :param mimetype: The MIME type to send for the file. If not
- provided, it will try to detect it from the file name.
- :param as_attachment: Indicate to a browser that it should offer to
- save the file instead of displaying it.
- :param download_name: The default name browsers will use when saving
- the file. Defaults to the passed file name.
- :param conditional: Enable conditional and range responses based on
- request headers. Requires passing a file path and ``environ``.
- :param etag: Calculate an ETag for the file, which requires passing
- a file path. Can also be a string to use instead.
- :param last_modified: The last modified time to send for the file,
- in seconds. If not provided, it will try to detect it from the
- file path.
- :param max_age: How long the client should cache the file, in
- seconds. If set, ``Cache-Control`` will be ``public``, otherwise
- it will be ``no-cache`` to prefer conditional caching.
-
- .. versionchanged:: 2.0
- ``download_name`` replaces the ``attachment_filename``
- parameter. If ``as_attachment=False``, it is passed with
- ``Content-Disposition: inline`` instead.
-
- .. versionchanged:: 2.0
- ``max_age`` replaces the ``cache_timeout`` parameter.
- ``conditional`` is enabled and ``max_age`` is not set by
- default.
-
- .. versionchanged:: 2.0
- ``etag`` replaces the ``add_etags`` parameter. It can be a
- string to use instead of generating one.
-
- .. versionchanged:: 2.0
- Passing a file-like object that inherits from
- :class:`~io.TextIOBase` will raise a :exc:`ValueError` rather
- than sending an empty file.
-
- .. versionadded:: 2.0
- Moved the implementation to Werkzeug. This is now a wrapper to
- pass some Flask-specific arguments.
-
- .. versionchanged:: 1.1
- ``filename`` may be a :class:`~os.PathLike` object.
-
- .. versionchanged:: 1.1
- Passing a :class:`~io.BytesIO` object supports range requests.
-
- .. versionchanged:: 1.0.3
- Filenames are encoded with ASCII instead of Latin-1 for broader
- compatibility with WSGI servers.
-
- .. versionchanged:: 1.0
- UTF-8 filenames as specified in :rfc:`2231` are supported.
-
- .. versionchanged:: 0.12
- The filename is no longer automatically inferred from file
- objects. If you want to use automatic MIME and etag support,
- pass a filename via ``filename_or_fp`` or
- ``attachment_filename``.
-
- .. versionchanged:: 0.12
- ``attachment_filename`` is preferred over ``filename`` for MIME
- detection.
-
- .. versionchanged:: 0.9
- ``cache_timeout`` defaults to
- :meth:`Flask.get_send_file_max_age`.
-
- .. versionchanged:: 0.7
- MIME guessing and etag support for file-like objects was
- deprecated because it was unreliable. Pass a filename if you are
- able to, otherwise attach an etag yourself.
-
- .. versionchanged:: 0.5
- The ``add_etags``, ``cache_timeout`` and ``conditional``
- parameters were added. The default behavior is to add etags.
-
- .. versionadded:: 0.2
- """
- return werkzeug.utils.send_file(
- **_prepare_send_file_kwargs(
- path_or_file=path_or_file,
- environ=request.environ,
- mimetype=mimetype,
- as_attachment=as_attachment,
- download_name=download_name,
- attachment_filename=attachment_filename,
- conditional=conditional,
- etag=etag,
- add_etags=add_etags,
- last_modified=last_modified,
- max_age=max_age,
- cache_timeout=cache_timeout,
- )
- )
-
-
-def safe_join(directory: str, *pathnames: str) -> str:
- """Safely join zero or more untrusted path components to a base
- directory to avoid escaping the base directory.
-
- :param directory: The trusted base directory.
- :param pathnames: The untrusted path components relative to the
- base directory.
- :return: A safe path, otherwise ``None``.
- """
- warnings.warn(
- "'flask.helpers.safe_join' is deprecated and will be removed in"
- " Flask 2.1. Use 'werkzeug.utils.safe_join' instead.",
- DeprecationWarning,
- stacklevel=2,
- )
- path = werkzeug.utils.safe_join(directory, *pathnames)
-
- if path is None:
- raise NotFound()
-
- return path
-
-
-def send_from_directory(
- directory: t.Union[os.PathLike, str],
- path: t.Union[os.PathLike, str],
- filename: t.Optional[str] = None,
- **kwargs: t.Any,
-) -> "Response":
- """Send a file from within a directory using :func:`send_file`.
-
- .. code-block:: python
-
- @app.route("/uploads/")
- def download_file(name):
- return send_from_directory(
- app.config['UPLOAD_FOLDER'], name, as_attachment=True
- )
-
- This is a secure way to serve files from a folder, such as static
- files or uploads. Uses :func:`~werkzeug.security.safe_join` to
- ensure the path coming from the client is not maliciously crafted to
- point outside the specified directory.
-
- If the final path does not point to an existing regular file,
- raises a 404 :exc:`~werkzeug.exceptions.NotFound` error.
-
- :param directory: The directory that ``path`` must be located under.
- :param path: The path to the file to send, relative to
- ``directory``.
- :param kwargs: Arguments to pass to :func:`send_file`.
-
- .. versionchanged:: 2.0
- ``path`` replaces the ``filename`` parameter.
-
- .. versionadded:: 2.0
- Moved the implementation to Werkzeug. This is now a wrapper to
- pass some Flask-specific arguments.
-
- .. versionadded:: 0.5
- """
- if filename is not None:
- warnings.warn(
- "The 'filename' parameter has been renamed to 'path'. The"
- " old name will be removed in Flask 2.1.",
- DeprecationWarning,
- stacklevel=2,
- )
- path = filename
-
- return werkzeug.utils.send_from_directory( # type: ignore
- directory, path, **_prepare_send_file_kwargs(**kwargs)
- )
-
-
-def get_root_path(import_name: str) -> str:
- """Find the root path of a package, or the path that contains a
- module. If it cannot be found, returns the current working
- directory.
-
- Not to be confused with the value returned by :func:`find_package`.
-
- :meta private:
- """
- # Module already imported and has a file attribute. Use that first.
- mod = sys.modules.get(import_name)
-
- if mod is not None and hasattr(mod, "__file__"):
- return os.path.dirname(os.path.abspath(mod.__file__))
-
- # Next attempt: check the loader.
- loader = pkgutil.get_loader(import_name)
-
- # Loader does not exist or we're referring to an unloaded main
- # module or a main module without path (interactive sessions), go
- # with the current working directory.
- if loader is None or import_name == "__main__":
- return os.getcwd()
-
- if hasattr(loader, "get_filename"):
- filepath = loader.get_filename(import_name) # type: ignore
- else:
- # Fall back to imports.
- __import__(import_name)
- mod = sys.modules[import_name]
- filepath = getattr(mod, "__file__", None)
-
- # If we don't have a file path it might be because it is a
- # namespace package. In this case pick the root path from the
- # first module that is contained in the package.
- if filepath is None:
- raise RuntimeError(
- "No root path can be found for the provided module"
- f" {import_name!r}. This can happen because the module"
- " came from an import hook that does not provide file"
- " name information or because it's a namespace package."
- " In this case the root path needs to be explicitly"
- " provided."
- )
-
- # filepath is import_name.py for a module, or __init__.py for a package.
- return os.path.dirname(os.path.abspath(filepath))
-
-
-class locked_cached_property(werkzeug.utils.cached_property):
- """A :func:`property` that is only evaluated once. Like
- :class:`werkzeug.utils.cached_property` except access uses a lock
- for thread safety.
-
- .. versionchanged:: 2.0
- Inherits from Werkzeug's ``cached_property`` (and ``property``).
- """
-
- def __init__(
- self,
- fget: t.Callable[[t.Any], t.Any],
- name: t.Optional[str] = None,
- doc: t.Optional[str] = None,
- ) -> None:
- super().__init__(fget, name=name, doc=doc)
- self.lock = RLock()
-
- def __get__(self, obj: object, type: type = None) -> t.Any: # type: ignore
- if obj is None:
- return self
-
- with self.lock:
- return super().__get__(obj, type=type)
-
- def __set__(self, obj: object, value: t.Any) -> None:
- with self.lock:
- super().__set__(obj, value)
-
- def __delete__(self, obj: object) -> None:
- with self.lock:
- super().__delete__(obj)
-
-
-def total_seconds(td: timedelta) -> int:
- """Returns the total seconds from a timedelta object.
-
- :param timedelta td: the timedelta to be converted in seconds
-
- :returns: number of seconds
- :rtype: int
-
- .. deprecated:: 2.0
- Will be removed in Flask 2.1. Use
- :meth:`timedelta.total_seconds` instead.
- """
- warnings.warn(
- "'total_seconds' is deprecated and will be removed in Flask"
- " 2.1. Use 'timedelta.total_seconds' instead.",
- DeprecationWarning,
- stacklevel=2,
- )
- return td.days * 60 * 60 * 24 + td.seconds
-
-
-def is_ip(value: str) -> bool:
- """Determine if the given string is an IP address.
-
- :param value: value to check
- :type value: str
-
- :return: True if string is an IP address
- :rtype: bool
- """
- for family in (socket.AF_INET, socket.AF_INET6):
- try:
- socket.inet_pton(family, value)
- except OSError:
- pass
- else:
- return True
-
- return False
-
-
-@lru_cache(maxsize=None)
-def _split_blueprint_path(name: str) -> t.List[str]:
- out: t.List[str] = [name]
-
- if "." in name:
- out.extend(_split_blueprint_path(name.rpartition(".")[0]))
-
- return out
diff --git a/venv/lib/python3.9/site-packages/flask/json/__init__.py b/venv/lib/python3.9/site-packages/flask/json/__init__.py
deleted file mode 100644
index 5780e20..0000000
--- a/venv/lib/python3.9/site-packages/flask/json/__init__.py
+++ /dev/null
@@ -1,350 +0,0 @@
-import io
-import json as _json
-import typing as t
-import uuid
-import warnings
-from datetime import date
-
-from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
-from werkzeug.http import http_date
-
-from ..globals import current_app
-from ..globals import request
-
-if t.TYPE_CHECKING:
- from ..app import Flask
- from ..wrappers import Response
-
-try:
- import dataclasses
-except ImportError:
- # Python < 3.7
- dataclasses = None # type: ignore
-
-
-class JSONEncoder(_json.JSONEncoder):
- """The default JSON encoder. Handles extra types compared to the
- built-in :class:`json.JSONEncoder`.
-
- - :class:`datetime.datetime` and :class:`datetime.date` are
- serialized to :rfc:`822` strings. This is the same as the HTTP
- date format.
- - :class:`uuid.UUID` is serialized to a string.
- - :class:`dataclasses.dataclass` is passed to
- :func:`dataclasses.asdict`.
- - :class:`~markupsafe.Markup` (or any object with a ``__html__``
- method) will call the ``__html__`` method to get a string.
-
- Assign a subclass of this to :attr:`flask.Flask.json_encoder` or
- :attr:`flask.Blueprint.json_encoder` to override the default.
- """
-
- def default(self, o: t.Any) -> t.Any:
- """Convert ``o`` to a JSON serializable type. See
- :meth:`json.JSONEncoder.default`. Python does not support
- overriding how basic types like ``str`` or ``list`` are
- serialized, they are handled before this method.
- """
- if isinstance(o, date):
- return http_date(o)
- if isinstance(o, uuid.UUID):
- return str(o)
- if dataclasses and dataclasses.is_dataclass(o):
- return dataclasses.asdict(o)
- if hasattr(o, "__html__"):
- return str(o.__html__())
- return super().default(o)
-
-
-class JSONDecoder(_json.JSONDecoder):
- """The default JSON decoder.
-
- This does not change any behavior from the built-in
- :class:`json.JSONDecoder`.
-
- Assign a subclass of this to :attr:`flask.Flask.json_decoder` or
- :attr:`flask.Blueprint.json_decoder` to override the default.
- """
-
-
-def _dump_arg_defaults(
- kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None
-) -> None:
- """Inject default arguments for dump functions."""
- if app is None:
- app = current_app
-
- if app:
- cls = app.json_encoder
- bp = app.blueprints.get(request.blueprint) if request else None # type: ignore
- if bp is not None and bp.json_encoder is not None:
- cls = bp.json_encoder
-
- kwargs.setdefault("cls", cls)
- kwargs.setdefault("ensure_ascii", app.config["JSON_AS_ASCII"])
- kwargs.setdefault("sort_keys", app.config["JSON_SORT_KEYS"])
- else:
- kwargs.setdefault("sort_keys", True)
- kwargs.setdefault("cls", JSONEncoder)
-
-
-def _load_arg_defaults(
- kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None
-) -> None:
- """Inject default arguments for load functions."""
- if app is None:
- app = current_app
-
- if app:
- cls = app.json_decoder
- bp = app.blueprints.get(request.blueprint) if request else None # type: ignore
- if bp is not None and bp.json_decoder is not None:
- cls = bp.json_decoder
-
- kwargs.setdefault("cls", cls)
- else:
- kwargs.setdefault("cls", JSONDecoder)
-
-
-def dumps(obj: t.Any, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> str:
- """Serialize an object to a string of JSON.
-
- Takes the same arguments as the built-in :func:`json.dumps`, with
- some defaults from application configuration.
-
- :param obj: Object to serialize to JSON.
- :param app: Use this app's config instead of the active app context
- or defaults.
- :param kwargs: Extra arguments passed to :func:`json.dumps`.
-
- .. versionchanged:: 2.0
- ``encoding`` is deprecated and will be removed in Flask 2.1.
-
- .. versionchanged:: 1.0.3
- ``app`` can be passed directly, rather than requiring an app
- context for configuration.
- """
- _dump_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop("encoding", None)
- rv = _json.dumps(obj, **kwargs)
-
- if encoding is not None:
- warnings.warn(
- "'encoding' is deprecated and will be removed in Flask 2.1.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if isinstance(rv, str):
- return rv.encode(encoding) # type: ignore
-
- return rv
-
-
-def dump(
- obj: t.Any, fp: t.IO[str], app: t.Optional["Flask"] = None, **kwargs: t.Any
-) -> None:
- """Serialize an object to JSON written to a file object.
-
- Takes the same arguments as the built-in :func:`json.dump`, with
- some defaults from application configuration.
-
- :param obj: Object to serialize to JSON.
- :param fp: File object to write JSON to.
- :param app: Use this app's config instead of the active app context
- or defaults.
- :param kwargs: Extra arguments passed to :func:`json.dump`.
-
- .. versionchanged:: 2.0
- Writing to a binary file, and the ``encoding`` argument, is
- deprecated and will be removed in Flask 2.1.
- """
- _dump_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop("encoding", None)
- show_warning = encoding is not None
-
- try:
- fp.write("")
- except TypeError:
- show_warning = True
- fp = io.TextIOWrapper(fp, encoding or "utf-8") # type: ignore
-
- if show_warning:
- warnings.warn(
- "Writing to a binary file, and the 'encoding' argument, is"
- " deprecated and will be removed in Flask 2.1.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- _json.dump(obj, fp, **kwargs)
-
-
-def loads(s: str, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.Any:
- """Deserialize an object from a string of JSON.
-
- Takes the same arguments as the built-in :func:`json.loads`, with
- some defaults from application configuration.
-
- :param s: JSON string to deserialize.
- :param app: Use this app's config instead of the active app context
- or defaults.
- :param kwargs: Extra arguments passed to :func:`json.loads`.
-
- .. versionchanged:: 2.0
- ``encoding`` is deprecated and will be removed in Flask 2.1. The
- data must be a string or UTF-8 bytes.
-
- .. versionchanged:: 1.0.3
- ``app`` can be passed directly, rather than requiring an app
- context for configuration.
- """
- _load_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop("encoding", None)
-
- if encoding is not None:
- warnings.warn(
- "'encoding' is deprecated and will be removed in Flask 2.1."
- " The data must be a string or UTF-8 bytes.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if isinstance(s, bytes):
- s = s.decode(encoding)
-
- return _json.loads(s, **kwargs)
-
-
-def load(fp: t.IO[str], app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.Any:
- """Deserialize an object from JSON read from a file object.
-
- Takes the same arguments as the built-in :func:`json.load`, with
- some defaults from application configuration.
-
- :param fp: File object to read JSON from.
- :param app: Use this app's config instead of the active app context
- or defaults.
- :param kwargs: Extra arguments passed to :func:`json.load`.
-
- .. versionchanged:: 2.0
- ``encoding`` is deprecated and will be removed in Flask 2.1. The
- file must be text mode, or binary mode with UTF-8 bytes.
- """
- _load_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop("encoding", None)
-
- if encoding is not None:
- warnings.warn(
- "'encoding' is deprecated and will be removed in Flask 2.1."
- " The file must be text mode, or binary mode with UTF-8"
- " bytes.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if isinstance(fp.read(0), bytes):
- fp = io.TextIOWrapper(fp, encoding) # type: ignore
-
- return _json.load(fp, **kwargs)
-
-
-def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str:
- """Serialize an object to a string of JSON with :func:`dumps`, then
- replace HTML-unsafe characters with Unicode escapes and mark the
- result safe with :class:`~markupsafe.Markup`.
-
- This is available in templates as the ``|tojson`` filter.
-
- The returned string is safe to render in HTML documents and
- ``
-
-
-
-
-"""
-FOOTER = """\
-
-
-
-
-
-
Console Locked
-
- The console is locked and needs to be unlocked by entering the PIN.
- You can find the PIN printed out on the standard output of your
- shell that runs the server.
-
-
-
-
-