Removed elitebot dir and some other stuff

This commit is contained in:
ComputerTech312 2024-02-20 14:29:15 +01:00
parent f5c3c95565
commit 2a8da606c2
1321 changed files with 3 additions and 554557 deletions

View file

@ -19,4 +19,4 @@
"Database": {
"ConnectionString": "mysql://user:password@host:port/database"
}
}
}

View file

@ -1,6 +1,6 @@
VERSION: 1.0.0
Connection:
Hostname: irc.rizon.net
Hostname: irc.example.net
Port: '+6697'
Nick: EliteBot
Ident: EliteBot

View file

@ -1,247 +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 VIRTUAL_ENV_PROMPT altogether.
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
}
# 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 virtual 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
}
$env:VIRTUAL_ENV_PROMPT = $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"

View file

@ -1,69 +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
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
VIRTUAL_ENV="/home/colby/Documents/stuff/EliteBot/elitebot"
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="(elitebot) ${PS1:-}"
export PS1
VIRTUAL_ENV_PROMPT="(elitebot) "
export VIRTUAL_ENV_PROMPT
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

View file

@ -1,26 +0,0 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV "/home/colby/Documents/stuff/EliteBot/elitebot"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = "(elitebot) $prompt"
setenv VIRTUAL_ENV_PROMPT "(elitebot) "
endif
alias pydoc python -m pydoc
rehash

View file

@ -1,69 +0,0 @@
# This file must be used with "source <venv>/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"
set -e _OLD_FISH_PROMPT_OVERRIDE
# prevents error when using nested fish instances (Issue #93858)
if functions -q _old_fish_prompt
functions -e fish_prompt
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
end
end
set -e VIRTUAL_ENV
set -e VIRTUAL_ENV_PROMPT
if test "$argv[1]" != "nondestructive"
# Self-destruct!
functions -e deactivate
end
end
# Unset irrelevant variables.
deactivate nondestructive
set -gx VIRTUAL_ENV "/home/colby/Documents/stuff/EliteBot/elitebot"
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) "(elitebot) " (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"
set -gx VIRTUAL_ENV_PROMPT "(elitebot) "
end

View file

@ -1,8 +0,0 @@
#!/home/colby/Documents/stuff/EliteBot/elitebot/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())

View file

@ -1,8 +0,0 @@
#!/home/colby/Documents/stuff/EliteBot/elitebot/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())

View file

@ -1,8 +0,0 @@
#!/home/colby/Documents/stuff/EliteBot/elitebot/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())

View file

@ -1 +0,0 @@
python3

View file

@ -1 +0,0 @@
/usr/bin/python3

View file

@ -1 +0,0 @@
python3

View file

@ -1,164 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/* Greenlet object interface */
#ifndef Py_GREENLETOBJECT_H
#define Py_GREENLETOBJECT_H
#include <Python.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is deprecated and undocumented. It does not change. */
#define GREENLET_VERSION "1.0.0"
#ifndef GREENLET_MODULE
#define implementation_ptr_t void*
#endif
typedef struct _greenlet {
PyObject_HEAD
PyObject* weakreflist;
PyObject* dict;
implementation_ptr_t pimpl;
} PyGreenlet;
#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type))
/* C API functions */
/* Total number of symbols that are exported */
#define PyGreenlet_API_pointers 12
#define PyGreenlet_Type_NUM 0
#define PyExc_GreenletError_NUM 1
#define PyExc_GreenletExit_NUM 2
#define PyGreenlet_New_NUM 3
#define PyGreenlet_GetCurrent_NUM 4
#define PyGreenlet_Throw_NUM 5
#define PyGreenlet_Switch_NUM 6
#define PyGreenlet_SetParent_NUM 7
#define PyGreenlet_MAIN_NUM 8
#define PyGreenlet_STARTED_NUM 9
#define PyGreenlet_ACTIVE_NUM 10
#define PyGreenlet_GET_PARENT_NUM 11
#ifndef GREENLET_MODULE
/* This section is used by modules that uses the greenlet C API */
static void** _PyGreenlet_API = NULL;
# define PyGreenlet_Type \
(*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM])
# define PyExc_GreenletError \
((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM])
# define PyExc_GreenletExit \
((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM])
/*
* PyGreenlet_New(PyObject *args)
*
* greenlet.greenlet(run, parent=None)
*/
# define PyGreenlet_New \
(*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \
_PyGreenlet_API[PyGreenlet_New_NUM])
/*
* PyGreenlet_GetCurrent(void)
*
* greenlet.getcurrent()
*/
# define PyGreenlet_GetCurrent \
(*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM])
/*
* PyGreenlet_Throw(
* PyGreenlet *greenlet,
* PyObject *typ,
* PyObject *val,
* PyObject *tb)
*
* g.throw(...)
*/
# define PyGreenlet_Throw \
(*(PyObject * (*)(PyGreenlet * self, \
PyObject * typ, \
PyObject * val, \
PyObject * tb)) \
_PyGreenlet_API[PyGreenlet_Throw_NUM])
/*
* PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args)
*
* g.switch(*args, **kwargs)
*/
# define PyGreenlet_Switch \
(*(PyObject * \
(*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \
_PyGreenlet_API[PyGreenlet_Switch_NUM])
/*
* PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent)
*
* g.parent = new_parent
*/
# define PyGreenlet_SetParent \
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
_PyGreenlet_API[PyGreenlet_SetParent_NUM])
/*
* PyGreenlet_GetParent(PyObject* greenlet)
*
* return greenlet.parent;
*
* This could return NULL even if there is no exception active.
* If it does not return NULL, you are responsible for decrementing the
* reference count.
*/
# define PyGreenlet_GetParent \
(*(PyGreenlet* (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_GET_PARENT_NUM])
/*
* deprecated, undocumented alias.
*/
# define PyGreenlet_GET_PARENT PyGreenlet_GetParent
# define PyGreenlet_MAIN \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_MAIN_NUM])
# define PyGreenlet_STARTED \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_STARTED_NUM])
# define PyGreenlet_ACTIVE \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_ACTIVE_NUM])
/* Macro that imports greenlet and initializes C API */
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
keep the older definition to be sure older code that might have a copy of
the header still works. */
# define PyGreenlet_Import() \
{ \
_PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \
}
#endif /* GREENLET_MODULE */
#ifdef __cplusplus
}
#endif
#endif /* !Py_GREENLETOBJECT_H */

View file

@ -1,20 +0,0 @@
Copyright (c) 2017-2021 Ingy döt Net
Copyright (c) 2006-2016 Kirill Simonov
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,46 +0,0 @@
Metadata-Version: 2.1
Name: PyYAML
Version: 6.0.1
Summary: YAML parser and emitter for Python
Home-page: https://pyyaml.org/
Download-URL: https://pypi.org/project/PyYAML/
Author: Kirill Simonov
Author-email: xi@resolvent.net
License: MIT
Project-URL: Bug Tracker, https://github.com/yaml/pyyaml/issues
Project-URL: CI, https://github.com/yaml/pyyaml/actions
Project-URL: Documentation, https://pyyaml.org/wiki/PyYAMLDocumentation
Project-URL: Mailing lists, http://lists.sourceforge.net/lists/listinfo/yaml-core
Project-URL: Source Code, https://github.com/yaml/pyyaml
Platform: Any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Cython
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: Markup
Requires-Python: >=3.6
License-File: LICENSE
YAML is a data serialization format designed for human readability
and interaction with scripting languages. PyYAML is a YAML parser
and emitter for Python.
PyYAML features a complete YAML 1.1 parser, Unicode support, pickle
support, capable extension API, and sensible error messages. PyYAML
supports standard YAML tags and provides Python-specific tags that
allow to represent an arbitrary Python object.
PyYAML is applicable for a broad range of tasks from complex
configuration files to object serialization and persistence.

View file

@ -1,44 +0,0 @@
PyYAML-6.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyYAML-6.0.1.dist-info/LICENSE,sha256=jTko-dxEkP1jVwfLiOsmvXZBAqcoKVQwfT5RZ6V36KQ,1101
PyYAML-6.0.1.dist-info/METADATA,sha256=UNNF8-SzzwOKXVo-kV5lXUGH2_wDWMBmGxqISpp5HQk,2058
PyYAML-6.0.1.dist-info/RECORD,,
PyYAML-6.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
PyYAML-6.0.1.dist-info/WHEEL,sha256=8KU227XctfdX2qUwyjQUO-ciQuZtmyPUCKmeGV6Byto,152
PyYAML-6.0.1.dist-info/top_level.txt,sha256=rpj0IVMTisAjh_1vG3Ccf9v5jpCQwAz6cD1IVU5ZdhQ,11
_yaml/__init__.py,sha256=04Ae_5osxahpJHa3XBZUAf4wi6XX32gR8D6X6p64GEA,1402
_yaml/__pycache__/__init__.cpython-311.pyc,,
yaml/__init__.py,sha256=bhl05qSeO-1ZxlSRjGrvl2m9nrXb1n9-GQatTN0Mrqc,12311
yaml/__pycache__/__init__.cpython-311.pyc,,
yaml/__pycache__/composer.cpython-311.pyc,,
yaml/__pycache__/constructor.cpython-311.pyc,,
yaml/__pycache__/cyaml.cpython-311.pyc,,
yaml/__pycache__/dumper.cpython-311.pyc,,
yaml/__pycache__/emitter.cpython-311.pyc,,
yaml/__pycache__/error.cpython-311.pyc,,
yaml/__pycache__/events.cpython-311.pyc,,
yaml/__pycache__/loader.cpython-311.pyc,,
yaml/__pycache__/nodes.cpython-311.pyc,,
yaml/__pycache__/parser.cpython-311.pyc,,
yaml/__pycache__/reader.cpython-311.pyc,,
yaml/__pycache__/representer.cpython-311.pyc,,
yaml/__pycache__/resolver.cpython-311.pyc,,
yaml/__pycache__/scanner.cpython-311.pyc,,
yaml/__pycache__/serializer.cpython-311.pyc,,
yaml/__pycache__/tokens.cpython-311.pyc,,
yaml/_yaml.cpython-311-x86_64-linux-gnu.so,sha256=ls52EONnCPWCytU6wojl6RE4BhAUdu8LH3XIYfgpH0k,2504120
yaml/composer.py,sha256=_Ko30Wr6eDWUeUpauUGT3Lcg9QPBnOPVlTnIMRGJ9FM,4883
yaml/constructor.py,sha256=kNgkfaeLUkwQYY_Q6Ff1Tz2XVw_pG1xVE9Ak7z-viLA,28639
yaml/cyaml.py,sha256=6ZrAG9fAYvdVe2FK_w0hmXoG7ZYsoYUwapG8CiC72H0,3851
yaml/dumper.py,sha256=PLctZlYwZLp7XmeUdwRuv4nYOZ2UBnDIUy8-lKfLF-o,2837
yaml/emitter.py,sha256=jghtaU7eFwg31bG0B7RZea_29Adi9CKmXq_QjgQpCkQ,43006
yaml/error.py,sha256=Ah9z-toHJUbE9j-M8YpxgSRM5CgLCcwVzJgLLRF2Fxo,2533
yaml/events.py,sha256=50_TksgQiE4up-lKo_V-nBy-tAIxkIPQxY5qDhKCeHw,2445
yaml/loader.py,sha256=UVa-zIqmkFSCIYq_PgSGm4NSJttHY2Rf_zQ4_b1fHN0,2061
yaml/nodes.py,sha256=gPKNj8pKCdh2d4gr3gIYINnPOaOxGhJAUiYhGRnPE84,1440
yaml/parser.py,sha256=ilWp5vvgoHFGzvOZDItFoGjD6D42nhlZrZyjAwa0oJo,25495
yaml/reader.py,sha256=0dmzirOiDG4Xo41RnuQS7K9rkY3xjHiVasfDMNTqCNw,6794
yaml/representer.py,sha256=IuWP-cAW9sHKEnS0gCqSa894k1Bg4cgTxaDwIcbRQ-Y,14190
yaml/resolver.py,sha256=9L-VYfm4mWHxUD1Vg4X7rjDRK_7VZd6b92wzq7Y2IKY,9004
yaml/scanner.py,sha256=YEM3iLZSaQwXcQRg2l2R4MdT0zGP2F9eHkKGKnHyWQY,51279
yaml/serializer.py,sha256=ChuFgmhU01hj4xgI8GaKv6vfM2Bujwa9i7d2FAHj7cA,4165
yaml/tokens.py,sha256=lTQIzSVw8Mg9wv459-TjiOQe6wVziqaRlqX2_89rp54,2573

View file

@ -1,6 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.40.0)
Root-Is-Purelib: false
Tag: cp311-cp311-manylinux_2_17_x86_64
Tag: cp311-cp311-manylinux2014_x86_64

View file

@ -1,19 +0,0 @@
Copyright 2005-2024 SQLAlchemy authors and contributors <see AUTHORS file>.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,242 +0,0 @@
Metadata-Version: 2.1
Name: SQLAlchemy
Version: 2.0.27
Summary: Database Abstraction Library
Home-page: https://www.sqlalchemy.org
Author: Mike Bayer
Author-email: mike_mp@zzzcomputing.com
License: MIT
Project-URL: Documentation, https://docs.sqlalchemy.org
Project-URL: Issue Tracker, https://github.com/sqlalchemy/sqlalchemy/
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Database :: Front-Ends
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE
Requires-Dist: typing-extensions >=4.6.0
Requires-Dist: greenlet !=0.4.17 ; platform_machine == "aarch64" or (platform_machine == "ppc64le" or (platform_machine == "x86_64" or (platform_machine == "amd64" or (platform_machine == "AMD64" or (platform_machine == "win32" or platform_machine == "WIN32")))))
Requires-Dist: importlib-metadata ; python_version < "3.8"
Provides-Extra: aiomysql
Requires-Dist: greenlet !=0.4.17 ; extra == 'aiomysql'
Requires-Dist: aiomysql >=0.2.0 ; extra == 'aiomysql'
Provides-Extra: aioodbc
Requires-Dist: greenlet !=0.4.17 ; extra == 'aioodbc'
Requires-Dist: aioodbc ; extra == 'aioodbc'
Provides-Extra: aiosqlite
Requires-Dist: greenlet !=0.4.17 ; extra == 'aiosqlite'
Requires-Dist: aiosqlite ; extra == 'aiosqlite'
Requires-Dist: typing-extensions !=3.10.0.1 ; extra == 'aiosqlite'
Provides-Extra: asyncio
Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncio'
Provides-Extra: asyncmy
Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncmy'
Requires-Dist: asyncmy !=0.2.4,!=0.2.6,>=0.2.3 ; extra == 'asyncmy'
Provides-Extra: mariadb_connector
Requires-Dist: mariadb !=1.1.2,!=1.1.5,>=1.0.1 ; extra == 'mariadb_connector'
Provides-Extra: mssql
Requires-Dist: pyodbc ; extra == 'mssql'
Provides-Extra: mssql_pymssql
Requires-Dist: pymssql ; extra == 'mssql_pymssql'
Provides-Extra: mssql_pyodbc
Requires-Dist: pyodbc ; extra == 'mssql_pyodbc'
Provides-Extra: mypy
Requires-Dist: mypy >=0.910 ; extra == 'mypy'
Provides-Extra: mysql
Requires-Dist: mysqlclient >=1.4.0 ; extra == 'mysql'
Provides-Extra: mysql_connector
Requires-Dist: mysql-connector-python ; extra == 'mysql_connector'
Provides-Extra: oracle
Requires-Dist: cx-oracle >=8 ; extra == 'oracle'
Provides-Extra: oracle_oracledb
Requires-Dist: oracledb >=1.0.1 ; extra == 'oracle_oracledb'
Provides-Extra: postgresql
Requires-Dist: psycopg2 >=2.7 ; extra == 'postgresql'
Provides-Extra: postgresql_asyncpg
Requires-Dist: greenlet !=0.4.17 ; extra == 'postgresql_asyncpg'
Requires-Dist: asyncpg ; extra == 'postgresql_asyncpg'
Provides-Extra: postgresql_pg8000
Requires-Dist: pg8000 >=1.29.1 ; extra == 'postgresql_pg8000'
Provides-Extra: postgresql_psycopg
Requires-Dist: psycopg >=3.0.7 ; extra == 'postgresql_psycopg'
Provides-Extra: postgresql_psycopg2binary
Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary'
Provides-Extra: postgresql_psycopg2cffi
Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi'
Provides-Extra: postgresql_psycopgbinary
Requires-Dist: psycopg[binary] >=3.0.7 ; extra == 'postgresql_psycopgbinary'
Provides-Extra: pymysql
Requires-Dist: pymysql ; extra == 'pymysql'
Provides-Extra: sqlcipher
Requires-Dist: sqlcipher3-binary ; extra == 'sqlcipher'
SQLAlchemy
==========
|PyPI| |Python| |Downloads|
.. |PyPI| image:: https://img.shields.io/pypi/v/sqlalchemy
:target: https://pypi.org/project/sqlalchemy
:alt: PyPI
.. |Python| image:: https://img.shields.io/pypi/pyversions/sqlalchemy
:target: https://pypi.org/project/sqlalchemy
:alt: PyPI - Python Version
.. |Downloads| image:: https://static.pepy.tech/badge/sqlalchemy/month
:target: https://pepy.tech/project/sqlalchemy
:alt: PyPI - Downloads
The Python SQL Toolkit and Object Relational Mapper
Introduction
-------------
SQLAlchemy is the Python SQL toolkit and Object Relational Mapper
that gives application developers the full power and
flexibility of SQL. SQLAlchemy provides a full suite
of well known enterprise-level persistence patterns,
designed for efficient and high-performing database
access, adapted into a simple and Pythonic domain
language.
Major SQLAlchemy features include:
* An industrial strength ORM, built
from the core on the identity map, unit of work,
and data mapper patterns. These patterns
allow transparent persistence of objects
using a declarative configuration system.
Domain models
can be constructed and manipulated naturally,
and changes are synchronized with the
current transaction automatically.
* A relationally-oriented query system, exposing
the full range of SQL's capabilities
explicitly, including joins, subqueries,
correlation, and most everything else,
in terms of the object model.
Writing queries with the ORM uses the same
techniques of relational composition you use
when writing SQL. While you can drop into
literal SQL at any time, it's virtually never
needed.
* A comprehensive and flexible system
of eager loading for related collections and objects.
Collections are cached within a session,
and can be loaded on individual access, all
at once using joins, or by query per collection
across the full result set.
* A Core SQL construction system and DBAPI
interaction layer. The SQLAlchemy Core is
separate from the ORM and is a full database
abstraction layer in its own right, and includes
an extensible Python-based SQL expression
language, schema metadata, connection pooling,
type coercion, and custom types.
* All primary and foreign key constraints are
assumed to be composite and natural. Surrogate
integer primary keys are of course still the
norm, but SQLAlchemy never assumes or hardcodes
to this model.
* Database introspection and generation. Database
schemas can be "reflected" in one step into
Python structures representing database metadata;
those same structures can then generate
CREATE statements right back out - all within
the Core, independent of the ORM.
SQLAlchemy's philosophy:
* SQL databases behave less and less like object
collections the more size and performance start to
matter; object collections behave less and less like
tables and rows the more abstraction starts to matter.
SQLAlchemy aims to accommodate both of these
principles.
* An ORM doesn't need to hide the "R". A relational
database provides rich, set-based functionality
that should be fully exposed. SQLAlchemy's
ORM provides an open-ended set of patterns
that allow a developer to construct a custom
mediation layer between a domain model and
a relational schema, turning the so-called
"object relational impedance" issue into
a distant memory.
* The developer, in all cases, makes all decisions
regarding the design, structure, and naming conventions
of both the object model as well as the relational
schema. SQLAlchemy only provides the means
to automate the execution of these decisions.
* With SQLAlchemy, there's no such thing as
"the ORM generated a bad query" - you
retain full control over the structure of
queries, including how joins are organized,
how subqueries and correlation is used, what
columns are requested. Everything SQLAlchemy
does is ultimately the result of a developer-initiated
decision.
* Don't use an ORM if the problem doesn't need one.
SQLAlchemy consists of a Core and separate ORM
component. The Core offers a full SQL expression
language that allows Pythonic construction
of SQL constructs that render directly to SQL
strings for a target database, returning
result sets that are essentially enhanced DBAPI
cursors.
* Transactions should be the norm. With SQLAlchemy's
ORM, nothing goes to permanent storage until
commit() is called. SQLAlchemy encourages applications
to create a consistent means of delineating
the start and end of a series of operations.
* Never render a literal value in a SQL statement.
Bound parameters are used to the greatest degree
possible, allowing query optimizers to cache
query plans effectively and making SQL injection
attacks a non-issue.
Documentation
-------------
Latest documentation is at:
https://www.sqlalchemy.org/docs/
Installation / Requirements
---------------------------
Full documentation for installation is at
`Installation <https://www.sqlalchemy.org/docs/intro.html#installation>`_.
Getting Help / Development / Bug reporting
------------------------------------------
Please refer to the `SQLAlchemy Community Guide <https://www.sqlalchemy.org/support.html>`_.
Code of Conduct
---------------
Above all, SQLAlchemy places great emphasis on polite, thoughtful, and
constructive communication between users and developers.
Please see our current Code of Conduct at
`Code of Conduct <https://www.sqlalchemy.org/codeofconduct.html>`_.
License
-------
SQLAlchemy is distributed under the `MIT license
<https://www.opensource.org/licenses/mit-license.php>`_.

View file

@ -1,530 +0,0 @@
SQLAlchemy-2.0.27.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
SQLAlchemy-2.0.27.dist-info/LICENSE,sha256=PA9Zq4h9BB3mpOUv_j6e212VIt6Qn66abNettue-MpM,1100
SQLAlchemy-2.0.27.dist-info/METADATA,sha256=fZGrNxgSqoY_vLjP6pXy7Ax_9Fvpy6P0SN_Qmjpaf8M,9602
SQLAlchemy-2.0.27.dist-info/RECORD,,
SQLAlchemy-2.0.27.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
SQLAlchemy-2.0.27.dist-info/WHEEL,sha256=AI1yqBLEPcVKWn5Ls2uPawjbqPXPFTYdQLSdN8WFCJw,152
SQLAlchemy-2.0.27.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11
sqlalchemy/__init__.py,sha256=s94qQVe-QqqRL9xhlih382KZikm_5rCLehCmTVeMkxo,13033
sqlalchemy/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/__pycache__/events.cpython-311.pyc,,
sqlalchemy/__pycache__/exc.cpython-311.pyc,,
sqlalchemy/__pycache__/inspection.cpython-311.pyc,,
sqlalchemy/__pycache__/log.cpython-311.pyc,,
sqlalchemy/__pycache__/schema.cpython-311.pyc,,
sqlalchemy/__pycache__/types.cpython-311.pyc,,
sqlalchemy/connectors/__init__.py,sha256=PzXPqZqi3BzEnrs1eW0DcsR4lyknAzhhN9rWcQ97hb4,476
sqlalchemy/connectors/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/connectors/__pycache__/aioodbc.cpython-311.pyc,,
sqlalchemy/connectors/__pycache__/asyncio.cpython-311.pyc,,
sqlalchemy/connectors/__pycache__/pyodbc.cpython-311.pyc,,
sqlalchemy/connectors/aioodbc.py,sha256=GSTiNMO9h0qjPxgqaxDwWZ8HvhWMFNVR6MJQnN1oc40,5288
sqlalchemy/connectors/asyncio.py,sha256=6s4hDYfuMjJ9KbJ4s7bF1fp5DmcgV77ozgZ5-bwZ0wc,5955
sqlalchemy/connectors/pyodbc.py,sha256=t7AjyxIOnaWg3CrlUEpBs4Y5l0HFdNt3P_cSSKhbi0Y,8501
sqlalchemy/cyextension/__init__.py,sha256=GzhhN8cjMnDTE0qerlUlpbrNmFPHQWCZ4Gk74OAxl04,244
sqlalchemy/cyextension/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/cyextension/collections.cpython-311-x86_64-linux-gnu.so,sha256=mMzAZiy3Z3NaEHsP_Ad-IvLCkvjbOZQCRwvS9PryJF4,2019496
sqlalchemy/cyextension/collections.pyx,sha256=L7DZ3DGKpgw2MT2ZZRRxCnrcyE5pU1NAFowWgAzQPEc,12571
sqlalchemy/cyextension/immutabledict.cpython-311-x86_64-linux-gnu.so,sha256=61zeVLfZ5ylDwnXZE8stoYcWJ1EcqMFiZid-L6Ihpss,703720
sqlalchemy/cyextension/immutabledict.pxd,sha256=3x3-rXG5eRQ7bBnktZ-OJ9-6ft8zToPmTDOd92iXpB0,291
sqlalchemy/cyextension/immutabledict.pyx,sha256=KfDTYbTfebstE8xuqAtuXsHNAK0_b5q_ymUiinUe_xs,3535
sqlalchemy/cyextension/processors.cpython-311-x86_64-linux-gnu.so,sha256=1kmZ0XQH06gEr1jQNF3PGAhFFd_5K4N4IAzyNTvce78,509544
sqlalchemy/cyextension/processors.pyx,sha256=R1rHsGLEaGeBq5VeCydjClzYlivERIJ9B-XLOJlf2MQ,1792
sqlalchemy/cyextension/resultproxy.cpython-311-x86_64-linux-gnu.so,sha256=EZDMIii55WxmoXp6I2QV0zAOaFYVQuglOfTZtTxUxCU,586752
sqlalchemy/cyextension/resultproxy.pyx,sha256=eWLdyBXiBy_CLQrF5ScfWJm7X0NeelscSXedtj1zv9Q,2725
sqlalchemy/cyextension/util.cpython-311-x86_64-linux-gnu.so,sha256=ArvZ5z3oRLSMODlTRYQ4LrPMyyBpf3SJ5py9jD_0QII,870136
sqlalchemy/cyextension/util.pyx,sha256=B85orxa9LddLuQEaDoVSq1XmAXIbLKxrxpvuB8ogV_o,2530
sqlalchemy/dialects/__init__.py,sha256=Kos9Gf5JZg1Vg6GWaCqEbD6e0r1jCwCmcnJIfcxDdcY,1770
sqlalchemy/dialects/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/dialects/__pycache__/_typing.cpython-311.pyc,,
sqlalchemy/dialects/_typing.py,sha256=hyv0nKucX2gI8ispB1IsvaUgrEPn9zEcq9hS7kfstEw,888
sqlalchemy/dialects/mssql/__init__.py,sha256=r5t8wFRNtBQoiUWh0WfIEWzXZW6f3D0uDt6NZTW_7Cc,1880
sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-311.pyc,,
sqlalchemy/dialects/mssql/__pycache__/base.cpython-311.pyc,,
sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-311.pyc,,
sqlalchemy/dialects/mssql/__pycache__/json.cpython-311.pyc,,
sqlalchemy/dialects/mssql/__pycache__/provision.cpython-311.pyc,,
sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-311.pyc,,
sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-311.pyc,,
sqlalchemy/dialects/mssql/aioodbc.py,sha256=UQd9ecSMIML713TDnLAviuBVJle7P7i1FtqGZZePk2Y,2022
sqlalchemy/dialects/mssql/base.py,sha256=2Tx9sC5bOd0JbweaMaqnjGOgESur7ZaaN1S66KMTwHk,133298
sqlalchemy/dialects/mssql/information_schema.py,sha256=HswjDc6y0mPXCf_x6VyylHlBdBa4PSY6Evxmmlch700,8084
sqlalchemy/dialects/mssql/json.py,sha256=evUACW2O62TAPq8B7QIPagz7jfc664ql9ms68JqiYzg,4816
sqlalchemy/dialects/mssql/provision.py,sha256=RTVbgYLFAHzEnpVQDJroU8ji_10MqBTiZfyP9_-QNT4,5362
sqlalchemy/dialects/mssql/pymssql.py,sha256=eZRLz7HGt3SdoZUjFBmA9BS43N7AhIASw7VPBPEJuG0,4038
sqlalchemy/dialects/mssql/pyodbc.py,sha256=vwM-vBlmRwrqxOc73P0sFOrBSwn24wzc5IkEOpalbXQ,27056
sqlalchemy/dialects/mysql/__init__.py,sha256=bxbi4hkysUK2OOVvr1F49akUj1cky27kKb07tgFzI9U,2153
sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/base.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/dml.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/expression.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/json.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/provision.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-311.pyc,,
sqlalchemy/dialects/mysql/__pycache__/types.cpython-311.pyc,,
sqlalchemy/dialects/mysql/aiomysql.py,sha256=67JrSUD1BmN88k_ASk6GvrttZFQiFjDY0wBiwdllxMk,9964
sqlalchemy/dialects/mysql/asyncmy.py,sha256=CGILIRKf_2Ut9Ng2yBlmdg62laL-ockEm6GMuN7xlKE,10033
sqlalchemy/dialects/mysql/base.py,sha256=KA7tvRxKUw0KwHwMth2rz-NWV0xMkVbYvPoBM9wrAFw,120850
sqlalchemy/dialects/mysql/cymysql.py,sha256=eXT1ry0w_qRxjiO24M980c-8PZ9qSsbhqBHntjEiKB0,2300
sqlalchemy/dialects/mysql/dml.py,sha256=HXJMAvimJsqvhj3UZO4vW_6LkF5RqaKbHvklAjor7yU,7645
sqlalchemy/dialects/mysql/enumerated.py,sha256=ipEPPQqoXfFwcywNdcLlZCEzHBtnitHRah1Gn6nItcg,8448
sqlalchemy/dialects/mysql/expression.py,sha256=lsmQCHKwfPezUnt27d2kR6ohk4IRFCA64KBS16kx5dc,4097
sqlalchemy/dialects/mysql/json.py,sha256=l6MEZ0qp8FgiRrIQvOMhyEJq0q6OqiEnvDTx5Cbt9uQ,2269
sqlalchemy/dialects/mysql/mariadb.py,sha256=kTfBLioLKk4JFFst4TY_iWqPtnvvQXFHknLfm89H2N8,853
sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=VVRwKLb6GzDmitOM4wLNvmZw6RdhnIwkLl7IZfAmUy8,8734
sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=qiQdfLPze3QHuASAZ9iqRzD0hDW8FbKoQnfAEQCF7tM,5675
sqlalchemy/dialects/mysql/mysqldb.py,sha256=9x_JiY4hj4tykG1ckuEGPyH4jCtsh4fgBhNukVnjUos,9658
sqlalchemy/dialects/mysql/provision.py,sha256=4oGkClQ8jC3YLPF54sB4kCjFc8HRTwf5zl5zftAAXGo,3474
sqlalchemy/dialects/mysql/pymysql.py,sha256=GUnSHd2M2uKjmN46Hheymtm26g7phEgwYOXrX0zLY8M,4083
sqlalchemy/dialects/mysql/pyodbc.py,sha256=072crI4qVyPhajYvHnsfFeSrNjLFVPIjBQKo5uyz5yk,4297
sqlalchemy/dialects/mysql/reflection.py,sha256=XXM8AGpaRTqDvuObg89Bzn_4h2ETG03viYBpWZJM3vc,22822
sqlalchemy/dialects/mysql/reserved_words.py,sha256=Dm7FINIAkrKLoXmdu26SpE6V8LDCGyp734nmHV2tMd0,9154
sqlalchemy/dialects/mysql/types.py,sha256=aPzx7hqqZ21aGwByEC-yWZUl6OpMvkbxwTqdN3OUGGI,24267
sqlalchemy/dialects/oracle/__init__.py,sha256=p4-2gw7TT0bX_MoJXTGD4i8WHctYsK9kCRbkpzykBrc,1493
sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/dialects/oracle/__pycache__/base.cpython-311.pyc,,
sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-311.pyc,,
sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-311.pyc,,
sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-311.pyc,,
sqlalchemy/dialects/oracle/__pycache__/provision.cpython-311.pyc,,
sqlalchemy/dialects/oracle/__pycache__/types.cpython-311.pyc,,
sqlalchemy/dialects/oracle/base.py,sha256=-7b5iubFPxJyDRoLXlxj8rk8eBRN2_IdZlB2zzzrrbw,118246
sqlalchemy/dialects/oracle/cx_oracle.py,sha256=t5yH4svVz7xoDSITF958blgZ01hbCUEWUKrAXwiCiAE,55566
sqlalchemy/dialects/oracle/dictionary.py,sha256=7WMrbPkqo8ZdGjaEZyQr-5f2pajSOF1OTGb8P97z8-g,19519
sqlalchemy/dialects/oracle/oracledb.py,sha256=UFcZwrrk0pWfAp_SKJZ1B5rIQHtNhOvuu73_JaSnTbI,9487
sqlalchemy/dialects/oracle/provision.py,sha256=O9ZpF4OG6Cx4mMzLRfZwhs8dZjrJETWR402n9c7726A,8304
sqlalchemy/dialects/oracle/types.py,sha256=QK3hJvWzKnnCe3oD3rItwEEIwcoBze8qGg7VFOvVlIk,8231
sqlalchemy/dialects/postgresql/__init__.py,sha256=kwgzMhtZKDHD12HMGo5MtdKCnDdy6wLezDGZPOEoU3Q,3895
sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/array.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/base.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/json.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/__pycache__/types.cpython-311.pyc,,
sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=7TudtgsPiSB8O5kX8W8KxcNYR8t5h_UHb86b_ChL0P8,5696
sqlalchemy/dialects/postgresql/array.py,sha256=9dJ_1WjWSBX1-MGDZtJACJ38vtRO3da7d4UId79WsnQ,13713
sqlalchemy/dialects/postgresql/asyncpg.py,sha256=12DN8hlK-Na_bEFmQ5kXK7MRqu87ze2IMX8aDyiSddU,40183
sqlalchemy/dialects/postgresql/base.py,sha256=ogY8rcQvT9jjYdtStxZ_nhTl8LmhB_zeJyhZIaUyMLk,176486
sqlalchemy/dialects/postgresql/dml.py,sha256=Pc69Le6qzmUHHb1FT5zeUSD31dWm6SBgdCAGW89cs3s,11212
sqlalchemy/dialects/postgresql/ext.py,sha256=1bZ--iNh2O9ym7l2gXZX48yP3yMO4dqb9RpYro2Mj2Q,16262
sqlalchemy/dialects/postgresql/hstore.py,sha256=otAx-RTDfpi_tcXkMuQV0JOIXtYgevgnsikLKKOkI6U,11541
sqlalchemy/dialects/postgresql/json.py,sha256=-ffnp85fQBOyt0Bjb7XAupmOxloUdzFZZgixUG3Wj5w,11212
sqlalchemy/dialects/postgresql/named_types.py,sha256=SFhs9_l108errKNuAMPl761RQ2imTO9PbUAnSv-WtRg,17100
sqlalchemy/dialects/postgresql/operators.py,sha256=NsAaWun_tL3d_be0fs9YL6T4LPKK6crnmFxxIJHgyeY,2808
sqlalchemy/dialects/postgresql/pg8000.py,sha256=3yoekiWSF-xnaWMqG76XrYPMqerg-42TdmfsW_ivK9E,18640
sqlalchemy/dialects/postgresql/pg_catalog.py,sha256=nAKavWTE_4cqxiDKDTdo-ivkCxxRIlzD5GO9Wl1yrG4,8884
sqlalchemy/dialects/postgresql/provision.py,sha256=yqyx-aDFO9l2YcL9f4T5HBP_Lnt5dHsMjpuXUG8mi7A,5762
sqlalchemy/dialects/postgresql/psycopg.py,sha256=TF53axr1EkTBAZD85JCq6wA7XTcJTzXueSz26txDbgc,22364
sqlalchemy/dialects/postgresql/psycopg2.py,sha256=gAP3poHDUxEB6iut6sxe9PhBiOrV_iIMvnP0NUlC-Rw,31607
sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=M7wAYSL6Pvt-4nbfacAHGyyw4XMKJ_bQZ1tc1pBtIdg,1756
sqlalchemy/dialects/postgresql/ranges.py,sha256=6CgV7qkxEMJ9AQsiibo_XBLJYzGh-2ZxpG83sRaesVY,32949
sqlalchemy/dialects/postgresql/types.py,sha256=Jfxqw9JaKNOq29JRWBublywgb3lLMyzx8YZI7CXpS2s,7300
sqlalchemy/dialects/sqlite/__init__.py,sha256=lp9DIggNn349M-7IYhUA8et8--e8FRExWD2V_r1LJk4,1182
sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/base.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/json.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-311.pyc,,
sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=OMvxP2eWyqk5beF-sHhzxRmjzO4VCQp55q7NH2XPVTE,12305
sqlalchemy/dialects/sqlite/base.py,sha256=lUtigjn7NdPBq831zQsLcBwdwRJqdgKM_tUaDrMElOE,96794
sqlalchemy/dialects/sqlite/dml.py,sha256=9GE55WvwoktKy2fHeT-Wbc9xPHgsbh5oBfd_fckMH5Q,8443
sqlalchemy/dialects/sqlite/json.py,sha256=Eoplbb_4dYlfrtmQaI8Xddd2suAIHA-IdbDQYM-LIhs,2777
sqlalchemy/dialects/sqlite/provision.py,sha256=UCpmwxf4IWlrpb2eLHGbPTpCFVbdI_KAh2mKtjiLYao,5632
sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=OL2S_05DK9kllZj6DOz7QtEl7jI7syxjW6woS725ii4,5356
sqlalchemy/dialects/sqlite/pysqlite.py,sha256=TAOqsHIjhbUZOF_Qk7UooiekkVZNhYJNduxlGQjokeA,27900
sqlalchemy/dialects/type_migration_guidelines.txt,sha256=-uHNdmYFGB7bzUNT6i8M5nb4j6j9YUKAtW4lcBZqsMg,8239
sqlalchemy/engine/__init__.py,sha256=Stb2oV6l8w65JvqEo6J4qtKoApcmOpXy3AAxQud4C1o,2818
sqlalchemy/engine/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/_py_processors.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/_py_row.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/_py_util.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/base.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/characteristics.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/create.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/cursor.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/default.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/events.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/interfaces.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/mock.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/processors.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/reflection.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/result.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/row.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/strategies.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/url.cpython-311.pyc,,
sqlalchemy/engine/__pycache__/util.cpython-311.pyc,,
sqlalchemy/engine/_py_processors.py,sha256=j9i_lcYYQOYJMcsDerPxI0sVFBIlX5sqoYMdMJlgWPI,3744
sqlalchemy/engine/_py_row.py,sha256=wSqoUFzLOJ1f89kgDb6sJm9LUrF5LMFpXPcK1vUsKcs,3787
sqlalchemy/engine/_py_util.py,sha256=f2DI3AN1kv6EplelowesCVpwS8hSXNufRkZoQmJtSH8,2484
sqlalchemy/engine/base.py,sha256=NGD1iokXsJBw_6sBOpX4STo_05fQFd52qUl1YiJZsdU,122038
sqlalchemy/engine/characteristics.py,sha256=Qbvt4CPrggJ3GfxHl0hOAxopjnCQy-W_pjtwLIe-Q1g,2590
sqlalchemy/engine/create.py,sha256=5Me7rgLvmZVJM6QzoH8aBHz0lIratA2vXN8cW6kUgdY,32872
sqlalchemy/engine/cursor.py,sha256=jSjpGM5DiwX1pwEHGx3wyqgHrgj8rwU5ZpVvMv5GaJs,74443
sqlalchemy/engine/default.py,sha256=VSqSm-juosz-5WqZPWjgDQf8Fra27M-YsrVVcs7RwPU,84672
sqlalchemy/engine/events.py,sha256=c0unNFFiHzTAvkUtXoJaxzMFMDwurBkHiiUhuN8qluc,37381
sqlalchemy/engine/interfaces.py,sha256=gktNzgLjNK-KrYMU__Lk0h85SXQI8LCjDakkuLxagNE,112688
sqlalchemy/engine/mock.py,sha256=yvpxgFmRw5G4QsHeF-ZwQGHKES-HqQOucTxFtN1uzdk,4179
sqlalchemy/engine/processors.py,sha256=XyfINKbo-2fjN-mW55YybvFyQMOil50_kVqsunahkNs,2379
sqlalchemy/engine/reflection.py,sha256=FlT5kPpKm7Lah50GNt5XcnlJWojTL3LD_x0SoCF9kfY,75127
sqlalchemy/engine/result.py,sha256=j6BI4Wj2bziQNQG5OlG_Cm4KcNWY9AoYvTXVlJUU-D8,77603
sqlalchemy/engine/row.py,sha256=9AAQo9zYDL88GcZ3bjcQTwMT-YIcuGTSMAyTfmBJ_yM,12032
sqlalchemy/engine/strategies.py,sha256=DqFSWaXJPL-29Omot9O0aOcuGL8KmCGyOvnPGDkAJoE,442
sqlalchemy/engine/url.py,sha256=8eWkUaIUyDExOcJ2D4xJXRcn4OY1GQJ3Q2duSX6UGAg,30784
sqlalchemy/engine/util.py,sha256=hkEql1t19WHl6uzR55-F-Fs_VMCJ7p02KKQVNUDSXTk,5667
sqlalchemy/event/__init__.py,sha256=KBrp622xojnC3FFquxa2JsMamwAbfkvzfv6Op0NKiYc,997
sqlalchemy/event/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/event/__pycache__/api.cpython-311.pyc,,
sqlalchemy/event/__pycache__/attr.cpython-311.pyc,,
sqlalchemy/event/__pycache__/base.cpython-311.pyc,,
sqlalchemy/event/__pycache__/legacy.cpython-311.pyc,,
sqlalchemy/event/__pycache__/registry.cpython-311.pyc,,
sqlalchemy/event/api.py,sha256=BUTAZjSlzvq4Hn2v2pihP_P1yo3lvCVDczK8lV_XJ80,8227
sqlalchemy/event/attr.py,sha256=X8QeHGK4ioSYht1vkhc11f606_mq_t91jMNIT314ubs,20751
sqlalchemy/event/base.py,sha256=3n9FmUkcXYHHyGzfpjKDsrIUVCNST_hq4zOtrNm0_a4,14954
sqlalchemy/event/legacy.py,sha256=teMPs00fO-4g8a_z2omcVKkYce5wj_1uvJO2n2MIeuo,8227
sqlalchemy/event/registry.py,sha256=nfTSSyhjZZXc5wseWB4sXn-YibSc0LKX8mg17XlWmAo,10835
sqlalchemy/events.py,sha256=k-ZD38aSPD29LYhED7CBqttp5MDVVx_YSaWC2-cu9ec,525
sqlalchemy/exc.py,sha256=M_8-O1hd8i6gbyx-TapV400p_Lxq2QqTGMXUAO-YgCc,23976
sqlalchemy/ext/__init__.py,sha256=S1fGKAbycnQDV01gs-JWGaFQ9GCD4QHwKcU2wnugg_o,322
sqlalchemy/ext/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/associationproxy.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/automap.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/baked.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/compiler.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/horizontal_shard.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/hybrid.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/indexable.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/instrumentation.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/mutable.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/orderinglist.cpython-311.pyc,,
sqlalchemy/ext/__pycache__/serializer.cpython-311.pyc,,
sqlalchemy/ext/associationproxy.py,sha256=5O5ANHARO8jytvqBQmOu-QjNVE4Hh3tfYquqKAj5ajs,65771
sqlalchemy/ext/asyncio/__init__.py,sha256=1OqSxEyIUn7RWLGyO12F-jAUIvk1I6DXlVy80-Gvkds,1317
sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/ext/asyncio/__pycache__/base.cpython-311.pyc,,
sqlalchemy/ext/asyncio/__pycache__/engine.cpython-311.pyc,,
sqlalchemy/ext/asyncio/__pycache__/exc.cpython-311.pyc,,
sqlalchemy/ext/asyncio/__pycache__/result.cpython-311.pyc,,
sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-311.pyc,,
sqlalchemy/ext/asyncio/__pycache__/session.cpython-311.pyc,,
sqlalchemy/ext/asyncio/base.py,sha256=fl7wxZD9KjgFiCtG3WXrYjHEvanamcsodCqq9pH9lOk,8905
sqlalchemy/ext/asyncio/engine.py,sha256=vQRdpBnGuyzyG48ZssDZvFlcS6Y6ZXUYI0GEOQqdDxk,47941
sqlalchemy/ext/asyncio/exc.py,sha256=8sII7VMXzs2TrhizhFQMzSfcroRtiesq8o3UwLfXSgQ,639
sqlalchemy/ext/asyncio/result.py,sha256=ID2eh-NHW-lnNFTxbKhje8fr-tnsucUsiw_jcpGcSPc,30409
sqlalchemy/ext/asyncio/scoping.py,sha256=BmE1UbFV_C4BXB4WngJc523DeMH-nTchNb8ORiSPYfE,52597
sqlalchemy/ext/asyncio/session.py,sha256=Zhkrwwc4rqZJntUpzbgruQNgpuOwaRmjrBQb8ol19z0,62894
sqlalchemy/ext/automap.py,sha256=hBlKAfZn2fgAAQh7vh4f2kClbb5ryOgV59tzVHEObQM,61389
sqlalchemy/ext/baked.py,sha256=H6T1il7GY84BhzPFj49UECSpZh_eBuiHomA-QIsYOYQ,17807
sqlalchemy/ext/compiler.py,sha256=ONPoxoKD2yUS9R2-oOhmPsA7efm-Bs0BXo7HE1dGlsU,20391
sqlalchemy/ext/declarative/__init__.py,sha256=20psLdFQbbOWfpdXHZ0CTY6I1k4UqXvKemNVu1LvPOI,1818
sqlalchemy/ext/declarative/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/ext/declarative/__pycache__/extensions.cpython-311.pyc,,
sqlalchemy/ext/declarative/extensions.py,sha256=uCjN1GisQt54AjqYnKYzJdUjnGd2pZBW47WWdPlS7FE,19547
sqlalchemy/ext/horizontal_shard.py,sha256=wuwAPnHymln0unSBnyx-cpX0AfESKSsypaSQTYCvzDk,16750
sqlalchemy/ext/hybrid.py,sha256=LXph2NOtBQj6rZMi5ar-WCxkY7qaFp-o-UFIvCy-ep0,52432
sqlalchemy/ext/indexable.py,sha256=UkTelbydKCdKelzbv3HWFFavoET9WocKaGRPGEOVfN8,11032
sqlalchemy/ext/instrumentation.py,sha256=sg8ghDjdHSODFXh_jAmpgemnNX1rxCeeXEG3-PMdrNk,15707
sqlalchemy/ext/mutable.py,sha256=L5ZkHBGYhMaqO75Xtyrk2DBR44RDk0g6Rz2HzHH0F8Q,37355
sqlalchemy/ext/mypy/__init__.py,sha256=0WebDIZmqBD0OTq5JLtd_PmfF9JGxe4d4Qv3Ml3PKUg,241
sqlalchemy/ext/mypy/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/ext/mypy/__pycache__/apply.cpython-311.pyc,,
sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-311.pyc,,
sqlalchemy/ext/mypy/__pycache__/infer.cpython-311.pyc,,
sqlalchemy/ext/mypy/__pycache__/names.cpython-311.pyc,,
sqlalchemy/ext/mypy/__pycache__/plugin.cpython-311.pyc,,
sqlalchemy/ext/mypy/__pycache__/util.cpython-311.pyc,,
sqlalchemy/ext/mypy/apply.py,sha256=Aek_-XA1eXihT4attxhfE43yBKtCgsxBSb--qgZKUqc,10550
sqlalchemy/ext/mypy/decl_class.py,sha256=1vVJRII2apnLTUbc5HkJS6Z2GueaUv_eKvhbqh7Wik4,17384
sqlalchemy/ext/mypy/infer.py,sha256=KVnmLFEVS33Al8pUKI7MJbJQu3KeveBUMl78EluBORw,19369
sqlalchemy/ext/mypy/names.py,sha256=IQ16GLZFqKxfYxIZxkbTurBqOUYbUV-64V_DSRns1tc,10630
sqlalchemy/ext/mypy/plugin.py,sha256=74ML8LI9xar0V86oCxnPFv5FQGEEfUzK64vOay4BKFs,9750
sqlalchemy/ext/mypy/util.py,sha256=1zuDQG8ezmF-XhJmAQU_lcBHiD--sL-lq20clg8t4lE,9448
sqlalchemy/ext/orderinglist.py,sha256=TGYbsGH72wEZcFNQDYDsZg9OSPuzf__P8YX8_2HtYUo,14384
sqlalchemy/ext/serializer.py,sha256=YemanWdeMVUDweHCnQc-iMO6mVVXNo2qQ5NK0Eb2_Es,6178
sqlalchemy/future/__init__.py,sha256=q2mw-gxk_xoxJLEvRoyMha3vO1xSRHrslcExOHZwmPA,512
sqlalchemy/future/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/future/__pycache__/engine.cpython-311.pyc,,
sqlalchemy/future/engine.py,sha256=AgIw6vMsef8W6tynOTkxsjd6o_OQDwGjLdbpoMD8ue8,495
sqlalchemy/inspection.py,sha256=MF-LE358wZDUEl1IH8-Uwt2HI65EsQpQW5o5udHkZwA,5063
sqlalchemy/log.py,sha256=8x9UR3nj0uFm6or6bQF-JWb4fYv2zOeQjG_w-0wOJFA,8607
sqlalchemy/orm/__init__.py,sha256=ZYys5nL3RFUDCMOLFDBrRI52F6er3S1U1OY9TeORuKs,8463
sqlalchemy/orm/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/_orm_constructors.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/_typing.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/attributes.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/base.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/bulk_persistence.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/clsregistry.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/collections.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/context.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/decl_api.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/decl_base.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/dependency.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/descriptor_props.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/dynamic.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/evaluator.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/events.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/exc.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/identity.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/instrumentation.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/interfaces.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/loading.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/mapped_collection.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/mapper.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/path_registry.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/persistence.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/properties.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/query.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/relationships.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/scoping.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/session.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/state.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/state_changes.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/strategies.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/strategy_options.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/sync.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/unitofwork.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/util.cpython-311.pyc,,
sqlalchemy/orm/__pycache__/writeonly.cpython-311.pyc,,
sqlalchemy/orm/_orm_constructors.py,sha256=VWY_MotbcQlECGx2uwEu3IcRkZ4RgLM_ufPad3IA9ZM,99354
sqlalchemy/orm/_typing.py,sha256=DVBfpHmDVK4x1zxaGJPY2GoTrAsyR6uexv20Lzf1afc,4973
sqlalchemy/orm/attributes.py,sha256=-IGg2RFjOPwAEr-boohvlZfitz7OtaXz1v8-7uG8ekw,92520
sqlalchemy/orm/base.py,sha256=HhuarpRU-BpKSHE1LeeBaG8CpdkwwLrvTkUVRK-ofjg,27424
sqlalchemy/orm/bulk_persistence.py,sha256=SSSR0Omv8A8BzpsOdSo4x75XICoqGpO1sUkyEWUVGso,70022
sqlalchemy/orm/clsregistry.py,sha256=29LyYiuj0qbebOpgW6DbBPNB2ikTweFQar1byCst7I0,17958
sqlalchemy/orm/collections.py,sha256=jpMsJGVixmrW9kfT8wevm9kpatKRqyDLcqWd7CjKPxE,52179
sqlalchemy/orm/context.py,sha256=Wjx0d1Rkxd-wsX1mP2V2_4VbOxdNY6S_HijdXJ-TtKg,112001
sqlalchemy/orm/decl_api.py,sha256=0gCZWM2sOXb_4OzUXfevVUisZWOUrErQTAHyaSQQL5k,63674
sqlalchemy/orm/decl_base.py,sha256=Tq6I3Jm3bkM01mmoiHfdFXLE94YDk1ik2u2dXL1RxLc,81601
sqlalchemy/orm/dependency.py,sha256=hgjksUWhgbmgHK5GdJdiDCBgDAIGQXIrY-Tj79tbL2k,47631
sqlalchemy/orm/descriptor_props.py,sha256=pKtpP7H1LB_YuHRVrEYpfFZybEnUUdPwQXxduYFe2hA,37180
sqlalchemy/orm/dynamic.py,sha256=jksBDCOsm6EBMVParcNGuMeaAv12hX4IzouKspC-HPA,9786
sqlalchemy/orm/evaluator.py,sha256=q292K5vdpP69G7Z9y1RqI5GFAk2diUPwnsXE8De_Wgw,11925
sqlalchemy/orm/events.py,sha256=_Ttun_bCSGgvsfg-VzAeEcsGpacf8p4c5z12JkSQkjM,127697
sqlalchemy/orm/exc.py,sha256=w7MZkJMGGlu5J6jOFSmi9XXzc02ctnTv34jrEWpI-eM,7356
sqlalchemy/orm/identity.py,sha256=jHdCxCpCyda_8mFOfGmN_Pr0XZdKiU-2hFZshlNxbHs,9249
sqlalchemy/orm/instrumentation.py,sha256=M-kZmkUvHUxtf-0mCA8RIM5QmMH1hWlYR_pKMwaidjA,24321
sqlalchemy/orm/interfaces.py,sha256=1yyppjMHcP5NPXjxfOlSeFNmc-3_T_o2upeF3KFZtc0,48378
sqlalchemy/orm/loading.py,sha256=JN2zLnPjNnk7K9DERbyerxESCXin7m7X1XP0gfdWLOE,57537
sqlalchemy/orm/mapped_collection.py,sha256=3cneB1dfPTLrsTvKoo9_oCY2xtq4UAHfe5WSXPyqIS4,19690
sqlalchemy/orm/mapper.py,sha256=8SVHr7tO-DDNpNGi68usc7PLQ7mTwzkZNEJu1aMb6dQ,171059
sqlalchemy/orm/path_registry.py,sha256=bIXllBRevK7Ic5irajYnZgl2iazJ0rKNRkhXJSlfxjY,25850
sqlalchemy/orm/persistence.py,sha256=dzyB2JOXNwQgaCbN8kh0sEz00WFePr48qf8NWVCUZH8,61701
sqlalchemy/orm/properties.py,sha256=81I-PIF7f7bB0qdH4BCYMWzCzRpe57yUiEIPv2tzBoA,29127
sqlalchemy/orm/query.py,sha256=UVNWn_Rq4a8agh5UUWNeu0DJQtPceCWVpXx1-uW7A4E,117555
sqlalchemy/orm/relationships.py,sha256=DqD3WBKpeVQ59ldh6eCxar_sIToA3tc2-bJPtp3zfpM,127709
sqlalchemy/orm/scoping.py,sha256=gFYywLeMmd5qjFdVPzeuCX727mTaChrCv8aqn4wPke0,78677
sqlalchemy/orm/session.py,sha256=yiKyoJBARQj4I1ZBjsIxc6ecCpt2Upjvlxruo2A5HRc,193181
sqlalchemy/orm/state.py,sha256=mW2f1hMSNeTJ89foutOE1EqLLD6DZkrSeO-pgagZweg,37520
sqlalchemy/orm/state_changes.py,sha256=qKYg7NxwrDkuUY3EPygAztym6oAVUFcP2wXn7QD3Mz4,6815
sqlalchemy/orm/strategies.py,sha256=OtmMtWpCDk4ZiaM_ipzGn80sPOi6Opwj3Co4lUHpd_w,114206
sqlalchemy/orm/strategy_options.py,sha256=RbFl-79Lrh8XIVUnZFmQ5GVvR586SG_szs3prw5DZLQ,84204
sqlalchemy/orm/sync.py,sha256=g7iZfSge1HgxMk9SKRgUgtHEbpbZ1kP_CBqOIdTOXqc,5779
sqlalchemy/orm/unitofwork.py,sha256=fiVaqcymbDDHRa1NjS90N9Z466nd5pkJOEi1dHO6QLY,27033
sqlalchemy/orm/util.py,sha256=MSLKAWZNw3FzFTH094xpfrhoA2Ov5pJQinK_dU_M0zo,80351
sqlalchemy/orm/writeonly.py,sha256=SYu2sAaHZONk2pW4PmtE871LG-O0P_bjidvKzY1H_zI,22305
sqlalchemy/pool/__init__.py,sha256=qiDdq4r4FFAoDrK6ncugF_i6usi_X1LeJt-CuBHey0s,1804
sqlalchemy/pool/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/pool/__pycache__/base.cpython-311.pyc,,
sqlalchemy/pool/__pycache__/events.cpython-311.pyc,,
sqlalchemy/pool/__pycache__/impl.cpython-311.pyc,,
sqlalchemy/pool/base.py,sha256=WF4az4ZKuzQGuKeSJeyexaYjmWZUvYdC6KIi8zTGodw,52236
sqlalchemy/pool/events.py,sha256=xGjkIUZl490ZDtCHqnQF9ZCwe2Jv93eGXmnQxftB11E,13147
sqlalchemy/pool/impl.py,sha256=2k2YMY9AepEoqGD_ClP_sUodSoa6atkt3GLPPWI49i4,17717
sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
sqlalchemy/schema.py,sha256=dKiWmgHYjcKQ4TiiD6vD0UMmIsD8u0Fsor1M9AAeGUs,3194
sqlalchemy/sql/__init__.py,sha256=UNa9EUiYWoPayf-FzNcwVgQvpsBdInPZfpJesAStN9o,5820
sqlalchemy/sql/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/_dml_constructors.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/_elements_constructors.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/_orm_types.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/_py_util.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/_typing.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/annotation.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/base.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/cache_key.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/coercions.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/compiler.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/crud.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/ddl.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/default_comparator.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/dml.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/elements.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/events.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/expression.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/functions.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/lambdas.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/naming.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/operators.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/roles.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/schema.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/selectable.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/sqltypes.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/traversals.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/type_api.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/util.cpython-311.pyc,,
sqlalchemy/sql/__pycache__/visitors.cpython-311.pyc,,
sqlalchemy/sql/_dml_constructors.py,sha256=YdBJex0MCVACv4q2nl_ii3uhxzwU6aDB8zAsratX5UQ,3867
sqlalchemy/sql/_elements_constructors.py,sha256=rrxq5Nzyo7GbLaGxb8VRZxko2nW0z7SYEli8ArfMIXI,62550
sqlalchemy/sql/_orm_types.py,sha256=T-vjcry4C1y0GToFKVxQCnmly_-Zsq4IO4SHN6bvUF4,625
sqlalchemy/sql/_py_util.py,sha256=hiM9ePbRSGs60bAMxPFuJCIC_p9SQ1VzqXGiPchiYwE,2173
sqlalchemy/sql/_selectable_constructors.py,sha256=wjE6HrLm9cR7bxvZXT8sFLUqT6t_J9G1XyQCnYmBDl0,18780
sqlalchemy/sql/_typing.py,sha256=Z3tBzapYRP0sKL7IwqnzPE9b8Bbq9vQtc4iV9tvxDoU,12494
sqlalchemy/sql/annotation.py,sha256=aqbbVz9kfbCT3_66CZ9GEirVN197Cukoqt8rq48FgkQ,18245
sqlalchemy/sql/base.py,sha256=2MVQnIL0b8xuzp1Fcv0NAye6h_OcgYpsUgLB4sy8Ahk,73756
sqlalchemy/sql/cache_key.py,sha256=sJhAA-2jovIteeIU7mw9hSL1liPP9Ez89CZZJFC3h6E,33548
sqlalchemy/sql/coercions.py,sha256=1xzN_9U5BCJGgokdc5iYj5o2cMAfEEZkr1Oa9Q-JYj8,40493
sqlalchemy/sql/compiler.py,sha256=aDD100xmz8WpBq8oe7PJ5ar8lk9emd54gEE5K2Hr76g,271187
sqlalchemy/sql/crud.py,sha256=g9xcol2KRGjZi1qsb2-bVz8zgVy_53gfMtJcnNO2vyQ,56521
sqlalchemy/sql/ddl.py,sha256=CIqMilCKfuQnF0lrZsQdTxgrbXqcTauKr0Ojzj77PFQ,45602
sqlalchemy/sql/default_comparator.py,sha256=utXWsZVGEjflhFfCT4ywa6RnhORc1Rryo87Hga71Rps,16707
sqlalchemy/sql/dml.py,sha256=pn0Lm1ofC5qVZzwGWFW73lPCiNba8OsTeemurJgwRyg,65614
sqlalchemy/sql/elements.py,sha256=kGRUilpx-rr6TTZgZpC5b71OnxxmCgDJRF2fYjDtxh8,172025
sqlalchemy/sql/events.py,sha256=iC_Q1Htm1Aobt5tOYxWfHHqNpoytrULORmUKcusH_-E,18290
sqlalchemy/sql/expression.py,sha256=VMX-dLpsZYnVRJpYNDozDUgaj7iQ0HuewUKVefD57PE,7586
sqlalchemy/sql/functions.py,sha256=MjXK0IVv45Y4n96_TMDZGJ7fwAhGHPRbFP8hOJgaplQ,63689
sqlalchemy/sql/lambdas.py,sha256=6P__bsWsFnrD7M18FPiBXI0L0OdWZOEV25FAijT4bwo,49289
sqlalchemy/sql/naming.py,sha256=ZHs1qSV3ou8TYmZ92uvU3sfdklUQlIz4uhe330n05SU,6858
sqlalchemy/sql/operators.py,sha256=r4oQp4h5zTMFFOpiFNV56joIK-QIjJCobatsmaZ-724,75935
sqlalchemy/sql/roles.py,sha256=pOsVn_OZD7mF2gJByHf24Rjopt0_Hu3dUCEOK5t4KS8,7662
sqlalchemy/sql/schema.py,sha256=WOIBaDVdg-zahrP95CPYgY4--3OQN56DH6xm28JDF-Y,228262
sqlalchemy/sql/selectable.py,sha256=7lxe79hZvnHyzHe1DobodI1lZ1eo8quSLZ6phw10Zj4,232848
sqlalchemy/sql/sqltypes.py,sha256=UV46KTkgxSin48oPckPOqk3Gx0tZT1l60qXwk7SbKlo,127101
sqlalchemy/sql/traversals.py,sha256=NFgJrVJzInO3HrnG90CklxrDXhFydZohPs2vRJkh3Bo,33589
sqlalchemy/sql/type_api.py,sha256=5DzdVquCJomFfpfMyLYbCb66PWxjxbSRdjh6UYB1Yv4,83841
sqlalchemy/sql/util.py,sha256=qGHQF-tPCj-m1FBerzT7weCanGcXU7dK5m-W7NHio-4,48077
sqlalchemy/sql/visitors.py,sha256=71wdVvhhZL4nJvVwFAs6ssaW-qZgNRSmKjpAcOzF_TA,36317
sqlalchemy/testing/__init__.py,sha256=VsrEHrORpAF5n7Vfl43YQgABh6EP1xBx_gHxs7pSXeE,3126
sqlalchemy/testing/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/assertions.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/assertsql.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/asyncio.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/config.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/engines.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/entities.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/exclusions.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/pickleable.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/profiling.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/provision.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/requirements.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/schema.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/util.cpython-311.pyc,,
sqlalchemy/testing/__pycache__/warnings.cpython-311.pyc,,
sqlalchemy/testing/assertions.py,sha256=gL0rA7CCZJbcVgvWOPV91tTZTRwQc1_Ta0-ykBn83Ew,31439
sqlalchemy/testing/assertsql.py,sha256=IgQG7l94WaiRP8nTbilJh1ZHZl125g7GPq-S5kmQZN0,16817
sqlalchemy/testing/asyncio.py,sha256=fkdRz-E37d5OrQKw5hdjmglOTJyXGnJzaJpvNXOBLxg,3728
sqlalchemy/testing/config.py,sha256=AqyH1qub_gDqX0BvlL-JBQe7N-t2wo8655FtwblUNOY,12090
sqlalchemy/testing/engines.py,sha256=UnH-8--3zLlYz4IbbCPwC375Za_DC61Spz-oKulbs9Q,13347
sqlalchemy/testing/entities.py,sha256=IphFegPKbff3Un47jY6bi7_MQXy6qkx_50jX2tHZJR4,3354
sqlalchemy/testing/exclusions.py,sha256=T8B01hmm8WVs-EKcUOQRzabahPqblWJfOidi6bHJ6GA,12460
sqlalchemy/testing/fixtures/__init__.py,sha256=dMClrIoxqlYIFpk2ia4RZpkbfxsS_3EBigr9QsPJ66g,1198
sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/testing/fixtures/__pycache__/base.cpython-311.pyc,,
sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-311.pyc,,
sqlalchemy/testing/fixtures/__pycache__/orm.cpython-311.pyc,,
sqlalchemy/testing/fixtures/__pycache__/sql.cpython-311.pyc,,
sqlalchemy/testing/fixtures/base.py,sha256=9r_J2ksiTzClpUxW0TczICHrWR7Ny8PV8IsBz6TsGFI,12256
sqlalchemy/testing/fixtures/mypy.py,sha256=gdxiwNFIzDlNGSOdvM3gbwDceVCC9t8oM5kKbwyhGBk,11973
sqlalchemy/testing/fixtures/orm.py,sha256=8EFbnaBbXX_Bf4FcCzBUaAHgyVpsLGBHX16SGLqE3Fg,6095
sqlalchemy/testing/fixtures/sql.py,sha256=MFOuYBUyPIpHJzjRCHL9vU-IT4bD6LXGGMvsp0v1FY8,15704
sqlalchemy/testing/pickleable.py,sha256=U9mIqk-zaxq9Xfy7HErP7UrKgTov-A3QFnhZh-NiOjI,2833
sqlalchemy/testing/plugin/__init__.py,sha256=79F--BIY_NTBzVRIlJGgAY5LNJJ3cD19XvrAo4X0W9A,247
sqlalchemy/testing/plugin/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-311.pyc,,
sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-311.pyc,,
sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-311.pyc,,
sqlalchemy/testing/plugin/bootstrap.py,sha256=oYScMbEW4pCnWlPEAq1insFruCXFQeEVBwo__i4McpU,1685
sqlalchemy/testing/plugin/plugin_base.py,sha256=BgNzWNEmgpK4CwhyblQQKnH-7FDKVi_Uul5vw8fFjBU,21578
sqlalchemy/testing/plugin/pytestplugin.py,sha256=Jtj073ArTcAmetv81sHmrUhlH0SblcSK4wyN8S4hmvo,27554
sqlalchemy/testing/profiling.py,sha256=PbuPhRFbauFilUONeY3tV_Y_5lBkD7iCa8VVyH2Sk9Y,10148
sqlalchemy/testing/provision.py,sha256=zXsw2D2Xpmw_chmYLsE1GXQqKQ-so3V8xU_joTcKan0,14619
sqlalchemy/testing/requirements.py,sha256=N9pSj7z2wVMkBif-DQfPVa_cl9k6p9g_J5FY1OsWtrY,51817
sqlalchemy/testing/schema.py,sha256=lr4GkGrGwagaHMuSGzWdzkMaj3HnS7dgfLLWfxt__-U,6513
sqlalchemy/testing/suite/__init__.py,sha256=Y5DRNG0Yl1u3ypt9zVF0Z9suPZeuO_UQGLl-wRgvTjU,722
sqlalchemy/testing/suite/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_cte.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_insert.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_results.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_select.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_types.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-311.pyc,,
sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-311.pyc,,
sqlalchemy/testing/suite/test_cte.py,sha256=6zBC3W2OwX1Xs-HedzchcKN2S7EaLNkgkvV_JSZ_Pq0,6451
sqlalchemy/testing/suite/test_ddl.py,sha256=1Npkf0C_4UNxphthAGjG078n0vPEgnSIHpDu5MfokxQ,12031
sqlalchemy/testing/suite/test_deprecations.py,sha256=BcJxZTcjYqeOAENVElCg3hVvU6fkGEW3KGBMfnW8bng,5337
sqlalchemy/testing/suite/test_dialect.py,sha256=EH4ZQWbnGdtjmx5amZtTyhYmrkXJCvW1SQoLahoE7uk,22923
sqlalchemy/testing/suite/test_insert.py,sha256=9azifj6-OCD7s8h_tAO1uPw100ibQv8YoKc_VA3hn3c,18824
sqlalchemy/testing/suite/test_reflection.py,sha256=tJSbJFg5fw0sSUv3I_FPmhN7rWWeJtq3YyxmylWJUlM,106466
sqlalchemy/testing/suite/test_results.py,sha256=NQ23m8FDVd0ub751jN4PswGoAhk5nrqvjHvpYULZXnc,15937
sqlalchemy/testing/suite/test_rowcount.py,sha256=3KDTlRgjpQ1OVfp__1cv8Hvq4CsDKzmrhJQ_WIJWoJg,7900
sqlalchemy/testing/suite/test_select.py,sha256=FvMFYQW9IJpDWGYZiJk46is6YrtmdSghBdTjZCG8T0Y,58574
sqlalchemy/testing/suite/test_sequence.py,sha256=66bCoy4xo99GBSaX6Hxb88foANAykLGRz1YEKbvpfuA,9923
sqlalchemy/testing/suite/test_types.py,sha256=rFmTOg6XuMch9L2-XthfLJRCTTwpZbMfrNss2g09gmc,65677
sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=c3_eIxLyORuSOhNDP0jWKxPyUf3SwMFpdalxtquwqlM,6141
sqlalchemy/testing/suite/test_update_delete.py,sha256=yTiM2unnfOK9rK8ZkqeTTU_MkT-RsKFLmdYliniZfAY,3994
sqlalchemy/testing/util.py,sha256=BFiSp3CEX95Dr-vv4l_7ZRu5vjZi9hjjnp-JKNfuS5E,14080
sqlalchemy/testing/warnings.py,sha256=fJ-QJUY2zY2PPxZJKv9medW-BKKbCNbA4Ns_V3YwFXM,1546
sqlalchemy/types.py,sha256=cQFM-hFRmaf1GErun1qqgEs6QxufvzMuwKqj9tuMPpE,3168
sqlalchemy/util/__init__.py,sha256=B3bedg-LSQEscwqgmYYU-VENUX8_zAE3q9vb7tkfJNY,8277
sqlalchemy/util/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy/util/__pycache__/_collections.cpython-311.pyc,,
sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-311.pyc,,
sqlalchemy/util/__pycache__/_has_cy.cpython-311.pyc,,
sqlalchemy/util/__pycache__/_py_collections.cpython-311.pyc,,
sqlalchemy/util/__pycache__/compat.cpython-311.pyc,,
sqlalchemy/util/__pycache__/concurrency.cpython-311.pyc,,
sqlalchemy/util/__pycache__/deprecations.cpython-311.pyc,,
sqlalchemy/util/__pycache__/langhelpers.cpython-311.pyc,,
sqlalchemy/util/__pycache__/preloaded.cpython-311.pyc,,
sqlalchemy/util/__pycache__/queue.cpython-311.pyc,,
sqlalchemy/util/__pycache__/tool_support.cpython-311.pyc,,
sqlalchemy/util/__pycache__/topological.cpython-311.pyc,,
sqlalchemy/util/__pycache__/typing.cpython-311.pyc,,
sqlalchemy/util/_collections.py,sha256=NE9dGJo8UNXIMbY3l3k8AO9BdPW04DlKTYraKCinchI,20063
sqlalchemy/util/_concurrency_py3k.py,sha256=v8VVoBfFvFHe4j8mMkVLfdUrTbV897p8RWGAm73Ue9U,8574
sqlalchemy/util/_has_cy.py,sha256=wCQmeSjT3jaH_oxfCEtGk-1g0gbSpt5MCK5UcWdMWqk,1247
sqlalchemy/util/_py_collections.py,sha256=U6L5AoyLdgSv7cdqB4xxQbw1rpeJjyOZVXffgxgga8I,16714
sqlalchemy/util/compat.py,sha256=R6bpBydldtbr6h7oJePihQxFb7jKiI-YDsK465MSOzk,8714
sqlalchemy/util/concurrency.py,sha256=mhwHm0utriD14DRqxTBWgIW7QuwdSEiLgLiJdUjiR3w,2427
sqlalchemy/util/deprecations.py,sha256=YBwvvYhSB8LhasIZRKvg_-WNoVhPUcaYI1ZrnjDn868,11971
sqlalchemy/util/langhelpers.py,sha256=khoFN05HjHiWY9ddeehCYxYG2u8LDzuiIKLOGLSAihU,64905
sqlalchemy/util/preloaded.py,sha256=az7NmLJLsqs0mtM9uBkIu10-841RYDq8wOyqJ7xXvqE,5904
sqlalchemy/util/queue.py,sha256=CaeSEaYZ57YwtmLdNdOIjT5PK_LCuwMFiO0mpp39ybM,10185
sqlalchemy/util/tool_support.py,sha256=9braZyidaiNrZVsWtGmkSmus50-byhuYrlAqvhjcmnA,6135
sqlalchemy/util/topological.py,sha256=N3M3Le7KzGHCmqPGg0ZBqixTDGwmFLhOZvBtc4rHL_g,3458
sqlalchemy/util/typing.py,sha256=FqH6WjV3p-8rz68YaXktpiZrPu3kmug2-gktJxBQSnI,16641

View file

@ -1,6 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.42.0)
Root-Is-Purelib: false
Tag: cp311-cp311-manylinux_2_17_x86_64
Tag: cp311-cp311-manylinux2014_x86_64

View file

@ -1,27 +0,0 @@
Copyright (c) 2012, Konsta Vesterinen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* 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.
* The names of the contributors may not 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 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.

View file

@ -1,97 +0,0 @@
Metadata-Version: 2.1
Name: SQLAlchemy-Utils
Version: 0.41.1
Summary: Various utility functions for SQLAlchemy.
Home-page: https://github.com/kvesteri/sqlalchemy-utils
Author: Konsta Vesterinen, Ryan Leckey, Janne Vanhala, Vesa Uimonen
Author-email: konsta@fastmonkeys.com
License: BSD
Platform: any
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.6
License-File: LICENSE
Requires-Dist: SQLAlchemy (>=1.3)
Requires-Dist: importlib-metadata ; python_version < "3.8"
Provides-Extra: arrow
Requires-Dist: arrow (>=0.3.4) ; extra == 'arrow'
Provides-Extra: babel
Requires-Dist: Babel (>=1.3) ; extra == 'babel'
Provides-Extra: color
Requires-Dist: colour (>=0.0.4) ; extra == 'color'
Provides-Extra: encrypted
Requires-Dist: cryptography (>=0.6) ; extra == 'encrypted'
Provides-Extra: intervals
Requires-Dist: intervals (>=0.7.1) ; extra == 'intervals'
Provides-Extra: password
Requires-Dist: passlib (<2.0,>=1.6) ; extra == 'password'
Provides-Extra: pendulum
Requires-Dist: pendulum (>=2.0.5) ; extra == 'pendulum'
Provides-Extra: phone
Requires-Dist: phonenumbers (>=5.9.2) ; extra == 'phone'
Provides-Extra: test
Requires-Dist: pytest (>=2.7.1) ; extra == 'test'
Requires-Dist: Pygments (>=1.2) ; extra == 'test'
Requires-Dist: Jinja2 (>=2.3) ; extra == 'test'
Requires-Dist: docutils (>=0.10) ; extra == 'test'
Requires-Dist: flexmock (>=0.9.7) ; extra == 'test'
Requires-Dist: psycopg (>=3.1.8) ; extra == 'test'
Requires-Dist: psycopg2 (>=2.5.1) ; extra == 'test'
Requires-Dist: psycopg2cffi (>=2.8.1) ; extra == 'test'
Requires-Dist: pg8000 (>=1.12.4) ; extra == 'test'
Requires-Dist: pytz (>=2014.2) ; extra == 'test'
Requires-Dist: python-dateutil (>=2.6) ; extra == 'test'
Requires-Dist: pymysql ; extra == 'test'
Requires-Dist: flake8 (>=2.4.0) ; extra == 'test'
Requires-Dist: isort (>=4.2.2) ; extra == 'test'
Requires-Dist: pyodbc ; extra == 'test'
Requires-Dist: backports.zoneinfo ; (python_version < "3.9") and extra == 'test'
Provides-Extra: test_all
Requires-Dist: Babel (>=1.3) ; extra == 'test_all'
Requires-Dist: Jinja2 (>=2.3) ; extra == 'test_all'
Requires-Dist: Pygments (>=1.2) ; extra == 'test_all'
Requires-Dist: arrow (>=0.3.4) ; extra == 'test_all'
Requires-Dist: colour (>=0.0.4) ; extra == 'test_all'
Requires-Dist: cryptography (>=0.6) ; extra == 'test_all'
Requires-Dist: docutils (>=0.10) ; extra == 'test_all'
Requires-Dist: flake8 (>=2.4.0) ; extra == 'test_all'
Requires-Dist: flexmock (>=0.9.7) ; extra == 'test_all'
Requires-Dist: furl (>=0.4.1) ; extra == 'test_all'
Requires-Dist: intervals (>=0.7.1) ; extra == 'test_all'
Requires-Dist: isort (>=4.2.2) ; extra == 'test_all'
Requires-Dist: passlib (<2.0,>=1.6) ; extra == 'test_all'
Requires-Dist: pendulum (>=2.0.5) ; extra == 'test_all'
Requires-Dist: pg8000 (>=1.12.4) ; extra == 'test_all'
Requires-Dist: phonenumbers (>=5.9.2) ; extra == 'test_all'
Requires-Dist: psycopg2 (>=2.5.1) ; extra == 'test_all'
Requires-Dist: psycopg2cffi (>=2.8.1) ; extra == 'test_all'
Requires-Dist: psycopg (>=3.1.8) ; extra == 'test_all'
Requires-Dist: pymysql ; extra == 'test_all'
Requires-Dist: pyodbc ; extra == 'test_all'
Requires-Dist: pytest (>=2.7.1) ; extra == 'test_all'
Requires-Dist: python-dateutil ; extra == 'test_all'
Requires-Dist: python-dateutil (>=2.6) ; extra == 'test_all'
Requires-Dist: pytz (>=2014.2) ; extra == 'test_all'
Requires-Dist: backports.zoneinfo ; (python_version < "3.9") and extra == 'test_all'
Provides-Extra: timezone
Requires-Dist: python-dateutil ; extra == 'timezone'
Provides-Extra: url
Requires-Dist: furl (>=0.4.1) ; extra == 'url'
SQLAlchemy-Utils
----------------
Various utility functions and custom data types for SQLAlchemy.

View file

@ -1,135 +0,0 @@
SQLAlchemy_Utils-0.41.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
SQLAlchemy_Utils-0.41.1.dist-info/LICENSE,sha256=aKpRvWCrOmo-gm2RyB2KhgP4FtG6tTWi_xi_fWmqmwo,1437
SQLAlchemy_Utils-0.41.1.dist-info/METADATA,sha256=L2ExcVhOidADc4LVJvw1RuF3ScQx3YMnaGGbkBlN-Ok,4341
SQLAlchemy_Utils-0.41.1.dist-info/RECORD,,
SQLAlchemy_Utils-0.41.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
SQLAlchemy_Utils-0.41.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
SQLAlchemy_Utils-0.41.1.dist-info/top_level.txt,sha256=C1ORFCU1fhRUCHEe-ZcUkfSkafW8gtZgCEAFeXZeaLc,17
sqlalchemy_utils/__init__.py,sha256=lQkpRiVlMTX8GuH5M6FIyntqMXlB2LcWBD1zK4x-c60,2363
sqlalchemy_utils/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/aggregates.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/asserts.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/compat.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/exceptions.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/expressions.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/generic.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/i18n.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/listeners.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/models.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/observer.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/operators.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/path.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/proxy_dict.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/query_chain.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/utils.cpython-311.pyc,,
sqlalchemy_utils/__pycache__/view.cpython-311.pyc,,
sqlalchemy_utils/aggregates.py,sha256=sdzDxpQDZgHmHMuEJ82vzMh8DDQEw7_vqaLBeRwn9ik,15420
sqlalchemy_utils/asserts.py,sha256=w37lkU4hgzlLkr3GalUMkGVRFrB4E65gi8vVeDNW5tE,5376
sqlalchemy_utils/compat.py,sha256=BYEgwN_tu-1yfjYSjVJEtK2R_WC57R7okXHoCv6aD4k,2241
sqlalchemy_utils/exceptions.py,sha256=iZW-TQSZDtCge4pzDDpYug4tKmpEM8coaplYiPJ8UPw,229
sqlalchemy_utils/expressions.py,sha256=ab-7JXJbuf9nNaSIEHGeUK9mkI__UpLrsAxgXYHZjCA,1610
sqlalchemy_utils/functions/__init__.py,sha256=R6TU8WdVGFrYOcA_76rW8CH8AvZeBR_SL6pJFdHa0g8,950
sqlalchemy_utils/functions/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy_utils/functions/__pycache__/database.cpython-311.pyc,,
sqlalchemy_utils/functions/__pycache__/foreign_keys.cpython-311.pyc,,
sqlalchemy_utils/functions/__pycache__/mock.cpython-311.pyc,,
sqlalchemy_utils/functions/__pycache__/orm.cpython-311.pyc,,
sqlalchemy_utils/functions/__pycache__/render.cpython-311.pyc,,
sqlalchemy_utils/functions/__pycache__/sort_query.cpython-311.pyc,,
sqlalchemy_utils/functions/database.py,sha256=eH2pTTRbCPrXFIsHcEjaH5SHugfKl-1SFQF_M7xyfcw,19986
sqlalchemy_utils/functions/foreign_keys.py,sha256=oHVJoB037tpa-xc3eVnhJPKT6YhkTDETVgQ5RIdIchg,10440
sqlalchemy_utils/functions/mock.py,sha256=g8PrPh7W2NFIyklSzKoL4s2cErvJXrAxMzGfvdif_48,3145
sqlalchemy_utils/functions/orm.py,sha256=sg9PfWFefRLGeMT_B8vcVDdLmn5EJjuUj9ImW-MNGqM,24628
sqlalchemy_utils/functions/render.py,sha256=aCAtzQicivrCMbCvaT-CdHhQvztr2yzAVFXHImzakH8,2057
sqlalchemy_utils/functions/sort_query.py,sha256=4O2vMDAwrPA2FsOY62xTirVmhqsfaDBGkRV_ReM7F4A,2332
sqlalchemy_utils/generic.py,sha256=LK11XwZa0gc8YEkykXVqVT48rYd6A2qCSsbc6asNJQM,6354
sqlalchemy_utils/i18n.py,sha256=bPJziNDTzIaSdNZntlgL0MlI3frQgf8M-yvyjmS_XoQ,3905
sqlalchemy_utils/listeners.py,sha256=p1nxzGnEWNspueH27iFG21D9_O-PX95wIWbgiNx5pHM,7805
sqlalchemy_utils/models.py,sha256=z87KGdLmwSRGeQBzEJ4w3jj5eEL3heEZPIfQYRPYniw,2877
sqlalchemy_utils/observer.py,sha256=11E_n4NwgRcqes0N6A1G8MKCTCGcznSvla2VkJdREPE,12220
sqlalchemy_utils/operators.py,sha256=nItfRvJbYcreLjCkJd7t1zckfidkvoiF-tMXNVUJz04,1966
sqlalchemy_utils/path.py,sha256=ulyUFuG5BAHIKr_ttJoa2s5NTzUKH27YYPrMLsy1Pew,4121
sqlalchemy_utils/primitives/__init__.py,sha256=Ubo8i8HJr2TIcA94y0I822FninJyxKSmHY676wZWT14,185
sqlalchemy_utils/primitives/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy_utils/primitives/__pycache__/country.cpython-311.pyc,,
sqlalchemy_utils/primitives/__pycache__/currency.cpython-311.pyc,,
sqlalchemy_utils/primitives/__pycache__/ltree.cpython-311.pyc,,
sqlalchemy_utils/primitives/__pycache__/weekday.cpython-311.pyc,,
sqlalchemy_utils/primitives/__pycache__/weekdays.cpython-311.pyc,,
sqlalchemy_utils/primitives/country.py,sha256=U8eayWirlksN2ZnCTLE4PFYnLU5DSnxs51m4FU2rVFM,2740
sqlalchemy_utils/primitives/currency.py,sha256=RdI-TIxhO90VCmzxnuOAd9ZvHkuw2XrzFJPvD5ZgfE8,2733
sqlalchemy_utils/primitives/ltree.py,sha256=4Hs6xjZKdNVMLiVppSCA37RoidfOQZWi7FlUWPuujHA,5261
sqlalchemy_utils/primitives/weekday.py,sha256=AMAe1km6iOKLlHghWUr8enj8J2jWNvf5Dox4LrneJJg,1259
sqlalchemy_utils/primitives/weekdays.py,sha256=K4tIOHv6EvYR3IUwCEqKT1DEiVgsBMpOty8xRym0Kcc,1764
sqlalchemy_utils/proxy_dict.py,sha256=t0-VwgrTcAAsUhOFCE2JdIhTy5Yv-71GebhwQC3xNIU,2369
sqlalchemy_utils/query_chain.py,sha256=GN6pWesgac5LtPTvUSecbciR9XbfBAG6qxdQiNFA38s,3963
sqlalchemy_utils/relationships/__init__.py,sha256=vyGb2Opfv-ZM0pw5JOpv9kdWr4_Q2foSHSp8Ho_cBik,3587
sqlalchemy_utils/relationships/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy_utils/relationships/__pycache__/chained_join.cpython-311.pyc,,
sqlalchemy_utils/relationships/chained_join.py,sha256=VUMZh5gwGf8qypkM-ZzNz3OtHY7mP7Hi0QoijQM6OpA,880
sqlalchemy_utils/types/__init__.py,sha256=LUMa5FZq7dFuzatd_Dl993hPHc8lQXSnHX4QlW0wG7E,1919
sqlalchemy_utils/types/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/arrow.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/bit.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/choice.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/color.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/country.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/currency.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/email.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/ip_address.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/json.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/locale.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/ltree.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/password.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/pg_composite.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/phone_number.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/range.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/scalar_coercible.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/scalar_list.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/timezone.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/ts_vector.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/url.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/uuid.cpython-311.pyc,,
sqlalchemy_utils/types/__pycache__/weekdays.cpython-311.pyc,,
sqlalchemy_utils/types/arrow.py,sha256=zpklt2Bh2rFPyjI2HBjMWWmbm83o6iiksp4yj9j1z-g,1535
sqlalchemy_utils/types/bit.py,sha256=V9TU63GCuPJGAjlDskK15kBwi2F2y_E9On34QQAY1Zs,756
sqlalchemy_utils/types/choice.py,sha256=3GNGs0qNgO3eR0xOlYEhbMjumTKGjMB1wAi-p5UuI5k,5882
sqlalchemy_utils/types/color.py,sha256=X5ogyU5s21wJYFhE9v_SttyYElV1BlnNFaZ2M0kTvJk,2121
sqlalchemy_utils/types/country.py,sha256=VQpj_5zL04u1mW6g9HKPp5pQlZoHmSXwW--wjj7DGtY,1579
sqlalchemy_utils/types/currency.py,sha256=7jab_GdPTZvaYjvsWwh8pyMj69iU2lpUwDsJy4_3YTo,1933
sqlalchemy_utils/types/email.py,sha256=93fleQPJrvdxZH9pjdPXtYnci96qwTIwdx3sJbvZNWk,1259
sqlalchemy_utils/types/encrypted/__init__.py,sha256=54Yf-Bd-HekcoRTJnHc5q0YVbAlJh8XMcPctgKTJGJo,28
sqlalchemy_utils/types/encrypted/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy_utils/types/encrypted/__pycache__/encrypted_type.cpython-311.pyc,,
sqlalchemy_utils/types/encrypted/__pycache__/padding.cpython-311.pyc,,
sqlalchemy_utils/types/encrypted/encrypted_type.py,sha256=Z7f48H-4JX1ngv2jmmfUPbYLIKoedZTCmmr73bm7plg,16646
sqlalchemy_utils/types/encrypted/padding.py,sha256=roNnoiCelBV-N1-UpOrBHZpL9tA7pkokcPeSNUrhfA8,4483
sqlalchemy_utils/types/enriched_datetime/__init__.py,sha256=OmaPAmpYTRsySUrf5V6YboLtq5cGMzjSkixzXg0g3fs,196
sqlalchemy_utils/types/enriched_datetime/__pycache__/__init__.cpython-311.pyc,,
sqlalchemy_utils/types/enriched_datetime/__pycache__/arrow_datetime.cpython-311.pyc,,
sqlalchemy_utils/types/enriched_datetime/__pycache__/enriched_date_type.cpython-311.pyc,,
sqlalchemy_utils/types/enriched_datetime/__pycache__/enriched_datetime_type.cpython-311.pyc,,
sqlalchemy_utils/types/enriched_datetime/__pycache__/pendulum_date.cpython-311.pyc,,
sqlalchemy_utils/types/enriched_datetime/__pycache__/pendulum_datetime.cpython-311.pyc,,
sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py,sha256=FsBohjRv800aIRIt-HCs_Hy7yV_MXYfS6fGzc9VdP2k,1038
sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py,sha256=ZcqeUk_2MqQR91pHvh0r4-bZmdeFnf49zVEIcSRnspQ,1367
sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py,sha256=N4BNnx4dqwbdltgxxm3GMNXvd744E2rSuTG-Iu2IKs8,1446
sqlalchemy_utils/types/enriched_datetime/pendulum_date.py,sha256=4gWAowdqxXWxkci5iKG6UrtYdAQ7ZbM4S4Br4Su7clA,868
sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py,sha256=FWGq--aTUDEOsjcmvSOYf3mpvQuwtUua4UFO2guJ8As,1451
sqlalchemy_utils/types/ip_address.py,sha256=d0W5H9ICIchWfGi76hkwOCZVVBsUiFS5ZE3HzJoHZwU,1327
sqlalchemy_utils/types/json.py,sha256=R_B-GkUwsqjsN0ncat9siWiTgITb-AS9LfLYZa5ilgQ,2123
sqlalchemy_utils/types/locale.py,sha256=4wJJ--wNUz_4Zj7u1-QSSRk_1VaF9fN6AjEmq-EL7sM,1797
sqlalchemy_utils/types/ltree.py,sha256=uS5Ry3GdXQzcXmYE57kCq_Orq22j_vIUSDtZLDi5UgA,3386
sqlalchemy_utils/types/password.py,sha256=GxfkBcnndSy-ihmqoECAY2YsgGJUpqGYzILg3x9gSD4,7875
sqlalchemy_utils/types/pg_composite.py,sha256=k6iPw3znq6U2fVhCUNykSTN4lrGpx5evxEwAfKcDQxA,10524
sqlalchemy_utils/types/phone_number.py,sha256=RTUiZbpw06e8Rt_N6Smgkh-lSNa27GidXysYx3ODFQ8,6707
sqlalchemy_utils/types/range.py,sha256=_nMDA-xL9rhYJby1gdLshZ8E9q2aR_rYd_8-3OrIT2A,12002
sqlalchemy_utils/types/scalar_coercible.py,sha256=cIG3kQKMPy6tktOQmexFZ_iDYzWzz3ky_x4jRZ38VFU,192
sqlalchemy_utils/types/scalar_list.py,sha256=ioi-hEIz6lC4E8ohQ_4SCTqvWYIHiNGxugzB3g1CeS8,2701
sqlalchemy_utils/types/timezone.py,sha256=RvtXS8OVoQvLvJVKpN5YjID7FcURwMJ9Vouh-lxO2Bk,3408
sqlalchemy_utils/types/ts_vector.py,sha256=WSOOGr8FXUIVe0HXhP-CSFAtCLDCyF07gMimfXQx8Rs,3148
sqlalchemy_utils/types/url.py,sha256=Gwa05HTM1ZKOBVWVk4AZ2WcydaQTAbwwANO8jp-SFmQ,1525
sqlalchemy_utils/types/uuid.py,sha256=NDkGm_NOcKyluKYT_tKgIWJX6WIk2kY8em-Md8a7Zc4,3297
sqlalchemy_utils/types/weekdays.py,sha256=u0AEc_sNnRNFKBYBfupby-7j7iBC3CWo5S2JDVC8mDE,2129
sqlalchemy_utils/utils.py,sha256=xFL2j2MxNiaKGFMrXOZsK8wMmqMItgtgSEgCExzsaIQ,452
sqlalchemy_utils/view.py,sha256=JPCxu4x74qIRDzIDahNJprE7sIYCJJ9P99Z9MNjsAOU,6468

View file

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.40.0)
Root-Is-Purelib: true
Tag: py3-none-any

View file

@ -1,227 +0,0 @@
# don't import any costly modules
import sys
import os
is_pypy = '__pypy__' in sys.builtin_module_names
def warn_distutils_present():
if 'distutils' not in sys.modules:
return
if is_pypy and sys.version_info < (3, 7):
# PyPy for 3.6 unconditionally imports distutils, so bypass the warning
# https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
return
import warnings
warnings.warn(
"Distutils was imported before Setuptools, but importing Setuptools "
"also replaces the `distutils` module in `sys.modules`. This may lead "
"to undesirable behaviors or errors. To avoid these issues, avoid "
"using distutils directly, ensure that setuptools is installed in the "
"traditional way (e.g. not an editable install), and/or make sure "
"that setuptools is always imported before distutils."
)
def clear_distutils():
if 'distutils' not in sys.modules:
return
import warnings
warnings.warn("Setuptools is replacing distutils.")
mods = [
name
for name in sys.modules
if name == "distutils" or name.startswith("distutils.")
]
for name in mods:
del sys.modules[name]
def enabled():
"""
Allow selection of distutils by environment variable.
"""
which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local')
return which == 'local'
def ensure_local_distutils():
import importlib
clear_distutils()
# With the DistutilsMetaFinder in place,
# perform an import to cause distutils to be
# loaded from setuptools._distutils. Ref #2906.
with shim():
importlib.import_module('distutils')
# check that submodules load as expected
core = importlib.import_module('distutils.core')
assert '_distutils' in core.__file__, core.__file__
assert 'setuptools._distutils.log' not in sys.modules
def do_override():
"""
Ensure that the local copy of distutils is preferred over stdlib.
See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
for more motivation.
"""
if enabled():
warn_distutils_present()
ensure_local_distutils()
class _TrivialRe:
def __init__(self, *patterns):
self._patterns = patterns
def match(self, string):
return all(pat in string for pat in self._patterns)
class DistutilsMetaFinder:
def find_spec(self, fullname, path, target=None):
# optimization: only consider top level modules and those
# found in the CPython test suite.
if path is not None and not fullname.startswith('test.'):
return
method_name = 'spec_for_{fullname}'.format(**locals())
method = getattr(self, method_name, lambda: None)
return method()
def spec_for_distutils(self):
if self.is_cpython():
return
import importlib
import importlib.abc
import importlib.util
try:
mod = importlib.import_module('setuptools._distutils')
except Exception:
# There are a couple of cases where setuptools._distutils
# may not be present:
# - An older Setuptools without a local distutils is
# taking precedence. Ref #2957.
# - Path manipulation during sitecustomize removes
# setuptools from the path but only after the hook
# has been loaded. Ref #2980.
# In either case, fall back to stdlib behavior.
return
class DistutilsLoader(importlib.abc.Loader):
def create_module(self, spec):
mod.__name__ = 'distutils'
return mod
def exec_module(self, module):
pass
return importlib.util.spec_from_loader(
'distutils', DistutilsLoader(), origin=mod.__file__
)
@staticmethod
def is_cpython():
"""
Suppress supplying distutils for CPython (build and tests).
Ref #2965 and #3007.
"""
return os.path.isfile('pybuilddir.txt')
def spec_for_pip(self):
"""
Ensure stdlib distutils when running under pip.
See pypa/pip#8761 for rationale.
"""
if sys.version_info >= (3, 12) or self.pip_imported_during_build():
return
clear_distutils()
self.spec_for_distutils = lambda: None
@classmethod
def pip_imported_during_build(cls):
"""
Detect if pip is being imported in a build script. Ref #2355.
"""
import traceback
return any(
cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None)
)
@staticmethod
def frame_file_is_setup(frame):
"""
Return True if the indicated frame suggests a setup.py file.
"""
# some frames may not have __file__ (#2940)
return frame.f_globals.get('__file__', '').endswith('setup.py')
def spec_for_sensitive_tests(self):
"""
Ensure stdlib distutils when running select tests under CPython.
python/cpython#91169
"""
clear_distutils()
self.spec_for_distutils = lambda: None
sensitive_tests = (
[
'test.test_distutils',
'test.test_peg_generator',
'test.test_importlib',
]
if sys.version_info < (3, 10)
else [
'test.test_distutils',
]
)
for name in DistutilsMetaFinder.sensitive_tests:
setattr(
DistutilsMetaFinder,
f'spec_for_{name}',
DistutilsMetaFinder.spec_for_sensitive_tests,
)
DISTUTILS_FINDER = DistutilsMetaFinder()
def add_shim():
DISTUTILS_FINDER in sys.meta_path or insert_shim()
class shim:
def __enter__(self):
insert_shim()
def __exit__(self, exc, value, tb):
_remove_shim()
def insert_shim():
sys.meta_path.insert(0, DISTUTILS_FINDER)
def _remove_shim():
try:
sys.meta_path.remove(DISTUTILS_FINDER)
except ValueError:
pass
if sys.version_info < (3, 12):
# DistutilsMetaFinder can only be disabled in Python < 3.12 (PEP 632)
remove_shim = _remove_shim

View file

@ -1 +0,0 @@
__import__('_distutils_hack').do_override()

View file

@ -1,33 +0,0 @@
# This is a stub package designed to roughly emulate the _yaml
# extension module, which previously existed as a standalone module
# and has been moved into the `yaml` package namespace.
# It does not perfectly mimic its old counterpart, but should get
# close enough for anyone who's relying on it even when they shouldn't.
import yaml
# in some circumstances, the yaml module we imoprted may be from a different version, so we need
# to tread carefully when poking at it here (it may not have the attributes we expect)
if not getattr(yaml, '__with_libyaml__', False):
from sys import version_info
exc = ModuleNotFoundError if version_info >= (3, 6) else ImportError
raise exc("No module named '_yaml'")
else:
from yaml._yaml import *
import warnings
warnings.warn(
'The _yaml extension module is now located at yaml._yaml'
' and its location is subject to change. To use the'
' LibYAML-based parser and emitter, import from `yaml`:'
' `from yaml import CLoader as Loader, CDumper as Dumper`.',
DeprecationWarning
)
del warnings
# Don't `del yaml` here because yaml is actually an existing
# namespace member of _yaml.
__name__ = '_yaml'
# If the module is top-level (i.e. not a part of any specific package)
# then the attribute should be set to ''.
# https://docs.python.org/3.8/library/types.html
__package__ = ''

View file

@ -1,441 +0,0 @@
Metadata-Version: 2.1
Name: colorama
Version: 0.4.6
Summary: Cross-platform colored terminal text.
Project-URL: Homepage, https://github.com/tartley/colorama
Author-email: Jonathan Hartley <tartley@tartley.com>
License-File: LICENSE.txt
Keywords: ansi,color,colour,crossplatform,terminal,text,windows,xplatform
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Terminals
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7
Description-Content-Type: text/x-rst
.. image:: https://img.shields.io/pypi/v/colorama.svg
:target: https://pypi.org/project/colorama/
:alt: Latest Version
.. image:: https://img.shields.io/pypi/pyversions/colorama.svg
:target: https://pypi.org/project/colorama/
:alt: Supported Python versions
.. image:: https://github.com/tartley/colorama/actions/workflows/test.yml/badge.svg
:target: https://github.com/tartley/colorama/actions/workflows/test.yml
:alt: Build Status
Colorama
========
Makes ANSI escape character sequences (for producing colored terminal text and
cursor positioning) work under MS Windows.
.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama&currency_code=USD
:alt: Donate with Paypal
`PyPI for releases <https://pypi.org/project/colorama/>`_ |
`Github for source <https://github.com/tartley/colorama>`_ |
`Colorama for enterprise on Tidelift <https://github.com/tartley/colorama/blob/master/ENTERPRISE.md>`_
If you find Colorama useful, please |donate| to the authors. Thank you!
Installation
------------
Tested on CPython 2.7, 3.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.8.
No requirements other than the standard library.
.. code-block:: bash
pip install colorama
# or
conda install -c anaconda colorama
Description
-----------
ANSI escape character sequences have long been used to produce colored terminal
text and cursor positioning on Unix and Macs. Colorama makes this work on
Windows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which
would appear as gobbledygook in the output), and converting them into the
appropriate win32 calls to modify the state of the terminal. On other platforms,
Colorama does nothing.
This has the upshot of providing a simple cross-platform API for printing
colored terminal text from Python, and has the happy side-effect that existing
applications or libraries which use ANSI sequences to produce colored output on
Linux or Macs can now also work on Windows, simply by calling
``colorama.just_fix_windows_console()`` (since v0.4.6) or ``colorama.init()``
(all versions, but may have other side-effects see below).
An alternative approach is to install ``ansi.sys`` on Windows machines, which
provides the same behaviour for all applications running in terminals. Colorama
is intended for situations where that isn't easy (e.g., maybe your app doesn't
have an installer.)
Demo scripts in the source code repository print some colored text using
ANSI sequences. Compare their output under Gnome-terminal's built in ANSI
handling, versus on Windows Command-Prompt using Colorama:
.. image:: https://github.com/tartley/colorama/raw/master/screenshots/ubuntu-demo.png
:width: 661
:height: 357
:alt: ANSI sequences on Ubuntu under gnome-terminal.
.. image:: https://github.com/tartley/colorama/raw/master/screenshots/windows-demo.png
:width: 668
:height: 325
:alt: Same ANSI sequences on Windows, using Colorama.
These screenshots show that, on Windows, Colorama does not support ANSI 'dim
text'; it looks the same as 'normal text'.
Usage
-----
Initialisation
..............
If the only thing you want from Colorama is to get ANSI escapes to work on
Windows, then run:
.. code-block:: python
from colorama import just_fix_windows_console
just_fix_windows_console()
If you're on a recent version of Windows 10 or better, and your stdout/stderr
are pointing to a Windows console, then this will flip the magic configuration
switch to enable Windows' built-in ANSI support.
If you're on an older version of Windows, and your stdout/stderr are pointing to
a Windows console, then this will wrap ``sys.stdout`` and/or ``sys.stderr`` in a
magic file object that intercepts ANSI escape sequences and issues the
appropriate Win32 calls to emulate them.
In all other circumstances, it does nothing whatsoever. Basically the idea is
that this makes Windows act like Unix with respect to ANSI escape handling.
It's safe to call this function multiple times. It's safe to call this function
on non-Windows platforms, but it won't do anything. It's safe to call this
function when one or both of your stdout/stderr are redirected to a file it
won't do anything to those streams.
Alternatively, you can use the older interface with more features (but also more
potential footguns):
.. code-block:: python
from colorama import init
init()
This does the same thing as ``just_fix_windows_console``, except for the
following differences:
- It's not safe to call ``init`` multiple times; you can end up with multiple
layers of wrapping and broken ANSI support.
- Colorama will apply a heuristic to guess whether stdout/stderr support ANSI,
and if it thinks they don't, then it will wrap ``sys.stdout`` and
``sys.stderr`` in a magic file object that strips out ANSI escape sequences
before printing them. This happens on all platforms, and can be convenient if
you want to write your code to emit ANSI escape sequences unconditionally, and
let Colorama decide whether they should actually be output. But note that
Colorama's heuristic is not particularly clever.
- ``init`` also accepts explicit keyword args to enable/disable various
functionality see below.
To stop using Colorama before your program exits, simply call ``deinit()``.
This will restore ``stdout`` and ``stderr`` to their original values, so that
Colorama is disabled. To resume using Colorama again, call ``reinit()``; it is
cheaper than calling ``init()`` again (but does the same thing).
Most users should depend on ``colorama >= 0.4.6``, and use
``just_fix_windows_console``. The old ``init`` interface will be supported
indefinitely for backwards compatibility, but we don't plan to fix any issues
with it, also for backwards compatibility.
Colored Output
..............
Cross-platform printing of colored text can then be done using Colorama's
constant shorthand for ANSI escape sequences. These are deliberately
rudimentary, see below.
.. code-block:: python
from colorama import Fore, Back, Style
print(Fore.RED + 'some red text')
print(Back.GREEN + 'and with a green background')
print(Style.DIM + 'and in dim text')
print(Style.RESET_ALL)
print('back to normal now')
...or simply by manually printing ANSI sequences from your own code:
.. code-block:: python
print('\033[31m' + 'some red text')
print('\033[39m') # and reset to default color
...or, Colorama can be used in conjunction with existing ANSI libraries
such as the venerable `Termcolor <https://pypi.org/project/termcolor/>`_
the fabulous `Blessings <https://pypi.org/project/blessings/>`_,
or the incredible `_Rich <https://pypi.org/project/rich/>`_.
If you wish Colorama's Fore, Back and Style constants were more capable,
then consider using one of the above highly capable libraries to generate
colors, etc, and use Colorama just for its primary purpose: to convert
those ANSI sequences to also work on Windows:
SIMILARLY, do not send PRs adding the generation of new ANSI types to Colorama.
We are only interested in converting ANSI codes to win32 API calls, not
shortcuts like the above to generate ANSI characters.
.. code-block:: python
from colorama import just_fix_windows_console
from termcolor import colored
# use Colorama to make Termcolor work on Windows too
just_fix_windows_console()
# then use Termcolor for all colored text output
print(colored('Hello, World!', 'green', 'on_red'))
Available formatting constants are::
Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.
Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.
Style: DIM, NORMAL, BRIGHT, RESET_ALL
``Style.RESET_ALL`` resets foreground, background, and brightness. Colorama will
perform this reset automatically on program exit.
These are fairly well supported, but not part of the standard::
Fore: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX
Back: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX
Cursor Positioning
..................
ANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for
an example of how to generate them.
Init Keyword Args
.................
``init()`` accepts some ``**kwargs`` to override default behaviour.
init(autoreset=False):
If you find yourself repeatedly sending reset sequences to turn off color
changes at the end of every print, then ``init(autoreset=True)`` will
automate that:
.. code-block:: python
from colorama import init
init(autoreset=True)
print(Fore.RED + 'some red text')
print('automatically back to default color again')
init(strip=None):
Pass ``True`` or ``False`` to override whether ANSI codes should be
stripped from the output. The default behaviour is to strip if on Windows
or if output is redirected (not a tty).
init(convert=None):
Pass ``True`` or ``False`` to override whether to convert ANSI codes in the
output into win32 calls. The default behaviour is to convert if on Windows
and output is to a tty (terminal).
init(wrap=True):
On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr``
with proxy objects, which override the ``.write()`` method to do their work.
If this wrapping causes you problems, then this can be disabled by passing
``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or
``strip`` or ``convert`` are True.
When wrapping is disabled, colored printing on non-Windows platforms will
continue to work as normal. To do cross-platform colored output, you can
use Colorama's ``AnsiToWin32`` proxy directly:
.. code-block:: python
import sys
from colorama import init, AnsiToWin32
init(wrap=False)
stream = AnsiToWin32(sys.stderr).stream
# Python 2
print >>stream, Fore.BLUE + 'blue text on stderr'
# Python 3
print(Fore.BLUE + 'blue text on stderr', file=stream)
Recognised ANSI Sequences
.........................
ANSI sequences generally take the form::
ESC [ <param> ; <param> ... <command>
Where ``<param>`` is an integer, and ``<command>`` is a single letter. Zero or
more params are passed to a ``<command>``. If no params are passed, it is
generally synonymous with passing a single zero. No spaces exist in the
sequence; they have been inserted here simply to read more easily.
The only ANSI sequences that Colorama converts into win32 calls are::
ESC [ 0 m # reset all (colors and brightness)
ESC [ 1 m # bright
ESC [ 2 m # dim (looks same as normal brightness)
ESC [ 22 m # normal brightness
# FOREGROUND:
ESC [ 30 m # black
ESC [ 31 m # red
ESC [ 32 m # green
ESC [ 33 m # yellow
ESC [ 34 m # blue
ESC [ 35 m # magenta
ESC [ 36 m # cyan
ESC [ 37 m # white
ESC [ 39 m # reset
# BACKGROUND
ESC [ 40 m # black
ESC [ 41 m # red
ESC [ 42 m # green
ESC [ 43 m # yellow
ESC [ 44 m # blue
ESC [ 45 m # magenta
ESC [ 46 m # cyan
ESC [ 47 m # white
ESC [ 49 m # reset
# cursor positioning
ESC [ y;x H # position cursor at x across, y down
ESC [ y;x f # position cursor at x across, y down
ESC [ n A # move cursor n lines up
ESC [ n B # move cursor n lines down
ESC [ n C # move cursor n characters forward
ESC [ n D # move cursor n characters backward
# clear the screen
ESC [ mode J # clear the screen
# clear the line
ESC [ mode K # clear the line
Multiple numeric params to the ``'m'`` command can be combined into a single
sequence::
ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background
All other ANSI sequences of the form ``ESC [ <param> ; <param> ... <command>``
are silently stripped from the output on Windows.
Any other form of ANSI sequence, such as single-character codes or alternative
initial characters, are not recognised or stripped. It would be cool to add
them though. Let me know if it would be useful for you, via the Issues on
GitHub.
Status & Known Problems
-----------------------
I've personally only tested it on Windows XP (CMD, Console2), Ubuntu
(gnome-terminal, xterm), and OS X.
Some valid ANSI sequences aren't recognised.
If you're hacking on the code, see `README-hacking.md`_. ESPECIALLY, see the
explanation there of why we do not want PRs that allow Colorama to generate new
types of ANSI codes.
See outstanding issues and wish-list:
https://github.com/tartley/colorama/issues
If anything doesn't work for you, or doesn't do what you expected or hoped for,
I'd love to hear about it on that issues list, would be delighted by patches,
and would be happy to grant commit access to anyone who submits a working patch
or two.
.. _README-hacking.md: README-hacking.md
License
-------
Copyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see
LICENSE file.
Professional support
--------------------
.. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png
:alt: Tidelift
:target: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme
.. list-table::
:widths: 10 100
* - |tideliftlogo|
- Professional support for colorama is available as part of the
`Tidelift Subscription`_.
Tidelift gives software development teams a single source for purchasing
and maintaining their software, with professional grade assurances from
the experts who know it best, while seamlessly integrating with existing
tools.
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme
Thanks
------
See the CHANGELOG for more thanks!
* Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5.
* Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``,
providing a solution to issue #7's setuptools/distutils debate,
and other fixes.
* User 'eryksun', for guidance on correctly instantiating ``ctypes.windll``.
* Matthew McCormick for politely pointing out a longstanding crash on non-Win.
* Ben Hoyt, for a magnificent fix under 64-bit Windows.
* Jesse at Empty Square for submitting a fix for examples in the README.
* User 'jamessp', an observant documentation fix for cursor positioning.
* User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7
fix.
* Julien Stuyck, for wisely suggesting Python3 compatible updates to README.
* Daniel Griffith for multiple fabulous patches.
* Oscar Lesta for a valuable fix to stop ANSI chars being sent to non-tty
output.
* Roger Binns, for many suggestions, valuable feedback, & bug reports.
* Tim Golden for thought and much appreciated feedback on the initial idea.
* User 'Zearin' for updates to the README file.
* John Szakmeister for adding support for light colors
* Charles Merriam for adding documentation to demos
* Jurko for a fix on 64-bit Windows CPython2.5 w/o ctypes
* Florian Bruhin for a fix when stdout or stderr are None
* Thomas Weininger for fixing ValueError on Windows
* Remi Rampin for better Github integration and fixes to the README file
* Simeon Visser for closing a file handle using 'with' and updating classifiers
to include Python 3.3 and 3.4
* Andy Neff for fixing RESET of LIGHT_EX colors.
* Jonathan Hartley for the initial idea and implementation.

View file

@ -1,32 +0,0 @@
colorama-0.4.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
colorama-0.4.6.dist-info/METADATA,sha256=e67SnrUMOym9sz_4TjF3vxvAV4T3aF7NyqRHHH3YEMw,17158
colorama-0.4.6.dist-info/RECORD,,
colorama-0.4.6.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
colorama-0.4.6.dist-info/WHEEL,sha256=cdcF4Fbd0FPtw2EMIOwH-3rSOTUdTCeOSXRMD1iLUb8,105
colorama-0.4.6.dist-info/licenses/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491
colorama/__init__.py,sha256=wePQA4U20tKgYARySLEC047ucNX-g8pRLpYBuiHlLb8,266
colorama/__pycache__/__init__.cpython-311.pyc,,
colorama/__pycache__/ansi.cpython-311.pyc,,
colorama/__pycache__/ansitowin32.cpython-311.pyc,,
colorama/__pycache__/initialise.cpython-311.pyc,,
colorama/__pycache__/win32.cpython-311.pyc,,
colorama/__pycache__/winterm.cpython-311.pyc,,
colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522
colorama/ansitowin32.py,sha256=vPNYa3OZbxjbuFyaVo0Tmhmy1FZ1lKMWCnT7odXpItk,11128
colorama/initialise.py,sha256=-hIny86ClXo39ixh5iSCfUIa2f_h_bgKRDW7gqs-KLU,3325
colorama/tests/__init__.py,sha256=MkgPAEzGQd-Rq0w0PZXSX2LadRWhUECcisJY8lSrm4Q,75
colorama/tests/__pycache__/__init__.cpython-311.pyc,,
colorama/tests/__pycache__/ansi_test.cpython-311.pyc,,
colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc,,
colorama/tests/__pycache__/initialise_test.cpython-311.pyc,,
colorama/tests/__pycache__/isatty_test.cpython-311.pyc,,
colorama/tests/__pycache__/utils.cpython-311.pyc,,
colorama/tests/__pycache__/winterm_test.cpython-311.pyc,,
colorama/tests/ansi_test.py,sha256=FeViDrUINIZcr505PAxvU4AjXz1asEiALs9GXMhwRaE,2839
colorama/tests/ansitowin32_test.py,sha256=RN7AIhMJ5EqDsYaCjVo-o4u8JzDD4ukJbmevWKS70rY,10678
colorama/tests/initialise_test.py,sha256=BbPy-XfyHwJ6zKozuQOvNvQZzsx9vdb_0bYXn7hsBTc,6741
colorama/tests/isatty_test.py,sha256=Pg26LRpv0yQDB5Ac-sxgVXG7hsA1NYvapFgApZfYzZg,1866
colorama/tests/utils.py,sha256=1IIRylG39z5-dzq09R_ngufxyPZxgldNbrxKxUGwGKE,1079
colorama/tests/winterm_test.py,sha256=qoWFPEjym5gm2RuMwpf3pOis3a5r_PJZFCzK254JL8A,3709
colorama/win32.py,sha256=YQOKwMTwtGBbsY4dL5HYTvwTeP9wIQra5MvPNddpxZs,6181
colorama/winterm.py,sha256=XCQFDHjPi6AHYNdZwy0tA02H-Jh48Jp-HvCjeLeLp3U,7134

View file

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: hatchling 1.11.1
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View file

@ -1,27 +0,0 @@
Copyright (c) 2010 Jonathan Hartley
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* 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.
* Neither the name of the copyright holders, nor those 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.

View file

@ -1,7 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
from .initialise import init, deinit, reinit, colorama_text, just_fix_windows_console
from .ansi import Fore, Back, Style, Cursor
from .ansitowin32 import AnsiToWin32
__version__ = '0.4.6'

View file

@ -1,102 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
'''
This module generates ANSI character codes to printing colors to terminals.
See: http://en.wikipedia.org/wiki/ANSI_escape_code
'''
CSI = '\033['
OSC = '\033]'
BEL = '\a'
def code_to_chars(code):
return CSI + str(code) + 'm'
def set_title(title):
return OSC + '2;' + title + BEL
def clear_screen(mode=2):
return CSI + str(mode) + 'J'
def clear_line(mode=2):
return CSI + str(mode) + 'K'
class AnsiCodes(object):
def __init__(self):
# the subclasses declare class attributes which are numbers.
# Upon instantiation we define instance attributes, which are the same
# as the class attributes but wrapped with the ANSI escape sequence
for name in dir(self):
if not name.startswith('_'):
value = getattr(self, name)
setattr(self, name, code_to_chars(value))
class AnsiCursor(object):
def UP(self, n=1):
return CSI + str(n) + 'A'
def DOWN(self, n=1):
return CSI + str(n) + 'B'
def FORWARD(self, n=1):
return CSI + str(n) + 'C'
def BACK(self, n=1):
return CSI + str(n) + 'D'
def POS(self, x=1, y=1):
return CSI + str(y) + ';' + str(x) + 'H'
class AnsiFore(AnsiCodes):
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
WHITE = 37
RESET = 39
# These are fairly well supported, but not part of the standard.
LIGHTBLACK_EX = 90
LIGHTRED_EX = 91
LIGHTGREEN_EX = 92
LIGHTYELLOW_EX = 93
LIGHTBLUE_EX = 94
LIGHTMAGENTA_EX = 95
LIGHTCYAN_EX = 96
LIGHTWHITE_EX = 97
class AnsiBack(AnsiCodes):
BLACK = 40
RED = 41
GREEN = 42
YELLOW = 43
BLUE = 44
MAGENTA = 45
CYAN = 46
WHITE = 47
RESET = 49
# These are fairly well supported, but not part of the standard.
LIGHTBLACK_EX = 100
LIGHTRED_EX = 101
LIGHTGREEN_EX = 102
LIGHTYELLOW_EX = 103
LIGHTBLUE_EX = 104
LIGHTMAGENTA_EX = 105
LIGHTCYAN_EX = 106
LIGHTWHITE_EX = 107
class AnsiStyle(AnsiCodes):
BRIGHT = 1
DIM = 2
NORMAL = 22
RESET_ALL = 0
Fore = AnsiFore()
Back = AnsiBack()
Style = AnsiStyle()
Cursor = AnsiCursor()

View file

@ -1,277 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import re
import sys
import os
from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style, BEL
from .winterm import enable_vt_processing, WinTerm, WinColor, WinStyle
from .win32 import windll, winapi_test
winterm = None
if windll is not None:
winterm = WinTerm()
class StreamWrapper(object):
'''
Wraps a stream (such as stdout), acting as a transparent proxy for all
attribute access apart from method 'write()', which is delegated to our
Converter instance.
'''
def __init__(self, wrapped, converter):
# double-underscore everything to prevent clashes with names of
# attributes on the wrapped stream object.
self.__wrapped = wrapped
self.__convertor = converter
def __getattr__(self, name):
return getattr(self.__wrapped, name)
def __enter__(self, *args, **kwargs):
# special method lookup bypasses __getattr__/__getattribute__, see
# https://stackoverflow.com/questions/12632894/why-doesnt-getattr-work-with-exit
# thus, contextlib magic methods are not proxied via __getattr__
return self.__wrapped.__enter__(*args, **kwargs)
def __exit__(self, *args, **kwargs):
return self.__wrapped.__exit__(*args, **kwargs)
def __setstate__(self, state):
self.__dict__ = state
def __getstate__(self):
return self.__dict__
def write(self, text):
self.__convertor.write(text)
def isatty(self):
stream = self.__wrapped
if 'PYCHARM_HOSTED' in os.environ:
if stream is not None and (stream is sys.__stdout__ or stream is sys.__stderr__):
return True
try:
stream_isatty = stream.isatty
except AttributeError:
return False
else:
return stream_isatty()
@property
def closed(self):
stream = self.__wrapped
try:
return stream.closed
# AttributeError in the case that the stream doesn't support being closed
# ValueError for the case that the stream has already been detached when atexit runs
except (AttributeError, ValueError):
return True
class AnsiToWin32(object):
'''
Implements a 'write()' method which, on Windows, will strip ANSI character
sequences from the text, and if outputting to a tty, will convert them into
win32 function calls.
'''
ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer
ANSI_OSC_RE = re.compile('\001?\033\\]([^\a]*)(\a)\002?') # Operating System Command
def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
# The wrapped stream (normally sys.stdout or sys.stderr)
self.wrapped = wrapped
# should we reset colors to defaults after every .write()
self.autoreset = autoreset
# create the proxy wrapping our output stream
self.stream = StreamWrapper(wrapped, self)
on_windows = os.name == 'nt'
# We test if the WinAPI works, because even if we are on Windows
# we may be using a terminal that doesn't support the WinAPI
# (e.g. Cygwin Terminal). In this case it's up to the terminal
# to support the ANSI codes.
conversion_supported = on_windows and winapi_test()
try:
fd = wrapped.fileno()
except Exception:
fd = -1
system_has_native_ansi = not on_windows or enable_vt_processing(fd)
have_tty = not self.stream.closed and self.stream.isatty()
need_conversion = conversion_supported and not system_has_native_ansi
# should we strip ANSI sequences from our output?
if strip is None:
strip = need_conversion or not have_tty
self.strip = strip
# should we should convert ANSI sequences into win32 calls?
if convert is None:
convert = need_conversion and have_tty
self.convert = convert
# dict of ansi codes to win32 functions and parameters
self.win32_calls = self.get_win32_calls()
# are we wrapping stderr?
self.on_stderr = self.wrapped is sys.stderr
def should_wrap(self):
'''
True if this class is actually needed. If false, then the output
stream will not be affected, nor will win32 calls be issued, so
wrapping stdout is not actually required. This will generally be
False on non-Windows platforms, unless optional functionality like
autoreset has been requested using kwargs to init()
'''
return self.convert or self.strip or self.autoreset
def get_win32_calls(self):
if self.convert and winterm:
return {
AnsiStyle.RESET_ALL: (winterm.reset_all, ),
AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT),
AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL),
AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL),
AnsiFore.BLACK: (winterm.fore, WinColor.BLACK),
AnsiFore.RED: (winterm.fore, WinColor.RED),
AnsiFore.GREEN: (winterm.fore, WinColor.GREEN),
AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW),
AnsiFore.BLUE: (winterm.fore, WinColor.BLUE),
AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA),
AnsiFore.CYAN: (winterm.fore, WinColor.CYAN),
AnsiFore.WHITE: (winterm.fore, WinColor.GREY),
AnsiFore.RESET: (winterm.fore, ),
AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True),
AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True),
AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True),
AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True),
AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True),
AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True),
AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True),
AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True),
AnsiBack.BLACK: (winterm.back, WinColor.BLACK),
AnsiBack.RED: (winterm.back, WinColor.RED),
AnsiBack.GREEN: (winterm.back, WinColor.GREEN),
AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW),
AnsiBack.BLUE: (winterm.back, WinColor.BLUE),
AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA),
AnsiBack.CYAN: (winterm.back, WinColor.CYAN),
AnsiBack.WHITE: (winterm.back, WinColor.GREY),
AnsiBack.RESET: (winterm.back, ),
AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True),
AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True),
AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True),
AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True),
AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True),
AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True),
AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True),
AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True),
}
return dict()
def write(self, text):
if self.strip or self.convert:
self.write_and_convert(text)
else:
self.wrapped.write(text)
self.wrapped.flush()
if self.autoreset:
self.reset_all()
def reset_all(self):
if self.convert:
self.call_win32('m', (0,))
elif not self.strip and not self.stream.closed:
self.wrapped.write(Style.RESET_ALL)
def write_and_convert(self, text):
'''
Write the given text to our wrapped stream, stripping any ANSI
sequences from the text, and optionally converting them into win32
calls.
'''
cursor = 0
text = self.convert_osc(text)
for match in self.ANSI_CSI_RE.finditer(text):
start, end = match.span()
self.write_plain_text(text, cursor, start)
self.convert_ansi(*match.groups())
cursor = end
self.write_plain_text(text, cursor, len(text))
def write_plain_text(self, text, start, end):
if start < end:
self.wrapped.write(text[start:end])
self.wrapped.flush()
def convert_ansi(self, paramstring, command):
if self.convert:
params = self.extract_params(command, paramstring)
self.call_win32(command, params)
def extract_params(self, command, paramstring):
if command in 'Hf':
params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';'))
while len(params) < 2:
# defaults:
params = params + (1,)
else:
params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0)
if len(params) == 0:
# defaults:
if command in 'JKm':
params = (0,)
elif command in 'ABCD':
params = (1,)
return params
def call_win32(self, command, params):
if command == 'm':
for param in params:
if param in self.win32_calls:
func_args = self.win32_calls[param]
func = func_args[0]
args = func_args[1:]
kwargs = dict(on_stderr=self.on_stderr)
func(*args, **kwargs)
elif command in 'J':
winterm.erase_screen(params[0], on_stderr=self.on_stderr)
elif command in 'K':
winterm.erase_line(params[0], on_stderr=self.on_stderr)
elif command in 'Hf': # cursor position - absolute
winterm.set_cursor_position(params, on_stderr=self.on_stderr)
elif command in 'ABCD': # cursor position - relative
n = params[0]
# A - up, B - down, C - forward, D - back
x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command]
winterm.cursor_adjust(x, y, on_stderr=self.on_stderr)
def convert_osc(self, text):
for match in self.ANSI_OSC_RE.finditer(text):
start, end = match.span()
text = text[:start] + text[end:]
paramstring, command = match.groups()
if command == BEL:
if paramstring.count(";") == 1:
params = paramstring.split(";")
# 0 - change title and icon (we will only change title)
# 1 - change icon (we don't support this)
# 2 - change title
if params[0] in '02':
winterm.set_title(params[1])
return text
def flush(self):
self.wrapped.flush()

View file

@ -1,121 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import atexit
import contextlib
import sys
from .ansitowin32 import AnsiToWin32
def _wipe_internal_state_for_tests():
global orig_stdout, orig_stderr
orig_stdout = None
orig_stderr = None
global wrapped_stdout, wrapped_stderr
wrapped_stdout = None
wrapped_stderr = None
global atexit_done
atexit_done = False
global fixed_windows_console
fixed_windows_console = False
try:
# no-op if it wasn't registered
atexit.unregister(reset_all)
except AttributeError:
# python 2: no atexit.unregister. Oh well, we did our best.
pass
def reset_all():
if AnsiToWin32 is not None: # Issue #74: objects might become None at exit
AnsiToWin32(orig_stdout).reset_all()
def init(autoreset=False, convert=None, strip=None, wrap=True):
if not wrap and any([autoreset, convert, strip]):
raise ValueError('wrap=False conflicts with any other arg=True')
global wrapped_stdout, wrapped_stderr
global orig_stdout, orig_stderr
orig_stdout = sys.stdout
orig_stderr = sys.stderr
if sys.stdout is None:
wrapped_stdout = None
else:
sys.stdout = wrapped_stdout = \
wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
if sys.stderr is None:
wrapped_stderr = None
else:
sys.stderr = wrapped_stderr = \
wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
global atexit_done
if not atexit_done:
atexit.register(reset_all)
atexit_done = True
def deinit():
if orig_stdout is not None:
sys.stdout = orig_stdout
if orig_stderr is not None:
sys.stderr = orig_stderr
def just_fix_windows_console():
global fixed_windows_console
if sys.platform != "win32":
return
if fixed_windows_console:
return
if wrapped_stdout is not None or wrapped_stderr is not None:
# Someone already ran init() and it did stuff, so we won't second-guess them
return
# On newer versions of Windows, AnsiToWin32.__init__ will implicitly enable the
# native ANSI support in the console as a side-effect. We only need to actually
# replace sys.stdout/stderr if we're in the old-style conversion mode.
new_stdout = AnsiToWin32(sys.stdout, convert=None, strip=None, autoreset=False)
if new_stdout.convert:
sys.stdout = new_stdout
new_stderr = AnsiToWin32(sys.stderr, convert=None, strip=None, autoreset=False)
if new_stderr.convert:
sys.stderr = new_stderr
fixed_windows_console = True
@contextlib.contextmanager
def colorama_text(*args, **kwargs):
init(*args, **kwargs)
try:
yield
finally:
deinit()
def reinit():
if wrapped_stdout is not None:
sys.stdout = wrapped_stdout
if wrapped_stderr is not None:
sys.stderr = wrapped_stderr
def wrap_stream(stream, convert, strip, autoreset, wrap):
if wrap:
wrapper = AnsiToWin32(stream,
convert=convert, strip=strip, autoreset=autoreset)
if wrapper.should_wrap():
stream = wrapper.stream
return stream
# Use this for initial setup as well, to reduce code duplication
_wipe_internal_state_for_tests()

View file

@ -1 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.

View file

@ -1,76 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import sys
from unittest import TestCase, main
from ..ansi import Back, Fore, Style
from ..ansitowin32 import AnsiToWin32
stdout_orig = sys.stdout
stderr_orig = sys.stderr
class AnsiTest(TestCase):
def setUp(self):
# sanity check: stdout should be a file or StringIO object.
# It will only be AnsiToWin32 if init() has previously wrapped it
self.assertNotEqual(type(sys.stdout), AnsiToWin32)
self.assertNotEqual(type(sys.stderr), AnsiToWin32)
def tearDown(self):
sys.stdout = stdout_orig
sys.stderr = stderr_orig
def testForeAttributes(self):
self.assertEqual(Fore.BLACK, '\033[30m')
self.assertEqual(Fore.RED, '\033[31m')
self.assertEqual(Fore.GREEN, '\033[32m')
self.assertEqual(Fore.YELLOW, '\033[33m')
self.assertEqual(Fore.BLUE, '\033[34m')
self.assertEqual(Fore.MAGENTA, '\033[35m')
self.assertEqual(Fore.CYAN, '\033[36m')
self.assertEqual(Fore.WHITE, '\033[37m')
self.assertEqual(Fore.RESET, '\033[39m')
# Check the light, extended versions.
self.assertEqual(Fore.LIGHTBLACK_EX, '\033[90m')
self.assertEqual(Fore.LIGHTRED_EX, '\033[91m')
self.assertEqual(Fore.LIGHTGREEN_EX, '\033[92m')
self.assertEqual(Fore.LIGHTYELLOW_EX, '\033[93m')
self.assertEqual(Fore.LIGHTBLUE_EX, '\033[94m')
self.assertEqual(Fore.LIGHTMAGENTA_EX, '\033[95m')
self.assertEqual(Fore.LIGHTCYAN_EX, '\033[96m')
self.assertEqual(Fore.LIGHTWHITE_EX, '\033[97m')
def testBackAttributes(self):
self.assertEqual(Back.BLACK, '\033[40m')
self.assertEqual(Back.RED, '\033[41m')
self.assertEqual(Back.GREEN, '\033[42m')
self.assertEqual(Back.YELLOW, '\033[43m')
self.assertEqual(Back.BLUE, '\033[44m')
self.assertEqual(Back.MAGENTA, '\033[45m')
self.assertEqual(Back.CYAN, '\033[46m')
self.assertEqual(Back.WHITE, '\033[47m')
self.assertEqual(Back.RESET, '\033[49m')
# Check the light, extended versions.
self.assertEqual(Back.LIGHTBLACK_EX, '\033[100m')
self.assertEqual(Back.LIGHTRED_EX, '\033[101m')
self.assertEqual(Back.LIGHTGREEN_EX, '\033[102m')
self.assertEqual(Back.LIGHTYELLOW_EX, '\033[103m')
self.assertEqual(Back.LIGHTBLUE_EX, '\033[104m')
self.assertEqual(Back.LIGHTMAGENTA_EX, '\033[105m')
self.assertEqual(Back.LIGHTCYAN_EX, '\033[106m')
self.assertEqual(Back.LIGHTWHITE_EX, '\033[107m')
def testStyleAttributes(self):
self.assertEqual(Style.DIM, '\033[2m')
self.assertEqual(Style.NORMAL, '\033[22m')
self.assertEqual(Style.BRIGHT, '\033[1m')
if __name__ == '__main__':
main()

View file

@ -1,294 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
from io import StringIO, TextIOWrapper
from unittest import TestCase, main
try:
from contextlib import ExitStack
except ImportError:
# python 2
from contextlib2 import ExitStack
try:
from unittest.mock import MagicMock, Mock, patch
except ImportError:
from mock import MagicMock, Mock, patch
from ..ansitowin32 import AnsiToWin32, StreamWrapper
from ..win32 import ENABLE_VIRTUAL_TERMINAL_PROCESSING
from .utils import osname
class StreamWrapperTest(TestCase):
def testIsAProxy(self):
mockStream = Mock()
wrapper = StreamWrapper(mockStream, None)
self.assertTrue( wrapper.random_attr is mockStream.random_attr )
def testDelegatesWrite(self):
mockStream = Mock()
mockConverter = Mock()
wrapper = StreamWrapper(mockStream, mockConverter)
wrapper.write('hello')
self.assertTrue(mockConverter.write.call_args, (('hello',), {}))
def testDelegatesContext(self):
mockConverter = Mock()
s = StringIO()
with StreamWrapper(s, mockConverter) as fp:
fp.write(u'hello')
self.assertTrue(s.closed)
def testProxyNoContextManager(self):
mockStream = MagicMock()
mockStream.__enter__.side_effect = AttributeError()
mockConverter = Mock()
with self.assertRaises(AttributeError) as excinfo:
with StreamWrapper(mockStream, mockConverter) as wrapper:
wrapper.write('hello')
def test_closed_shouldnt_raise_on_closed_stream(self):
stream = StringIO()
stream.close()
wrapper = StreamWrapper(stream, None)
self.assertEqual(wrapper.closed, True)
def test_closed_shouldnt_raise_on_detached_stream(self):
stream = TextIOWrapper(StringIO())
stream.detach()
wrapper = StreamWrapper(stream, None)
self.assertEqual(wrapper.closed, True)
class AnsiToWin32Test(TestCase):
def testInit(self):
mockStdout = Mock()
auto = Mock()
stream = AnsiToWin32(mockStdout, autoreset=auto)
self.assertEqual(stream.wrapped, mockStdout)
self.assertEqual(stream.autoreset, auto)
@patch('colorama.ansitowin32.winterm', None)
@patch('colorama.ansitowin32.winapi_test', lambda *_: True)
def testStripIsTrueOnWindows(self):
with osname('nt'):
mockStdout = Mock()
stream = AnsiToWin32(mockStdout)
self.assertTrue(stream.strip)
def testStripIsFalseOffWindows(self):
with osname('posix'):
mockStdout = Mock(closed=False)
stream = AnsiToWin32(mockStdout)
self.assertFalse(stream.strip)
def testWriteStripsAnsi(self):
mockStdout = Mock()
stream = AnsiToWin32(mockStdout)
stream.wrapped = Mock()
stream.write_and_convert = Mock()
stream.strip = True
stream.write('abc')
self.assertFalse(stream.wrapped.write.called)
self.assertEqual(stream.write_and_convert.call_args, (('abc',), {}))
def testWriteDoesNotStripAnsi(self):
mockStdout = Mock()
stream = AnsiToWin32(mockStdout)
stream.wrapped = Mock()
stream.write_and_convert = Mock()
stream.strip = False
stream.convert = False
stream.write('abc')
self.assertFalse(stream.write_and_convert.called)
self.assertEqual(stream.wrapped.write.call_args, (('abc',), {}))
def assert_autoresets(self, convert, autoreset=True):
stream = AnsiToWin32(Mock())
stream.convert = convert
stream.reset_all = Mock()
stream.autoreset = autoreset
stream.winterm = Mock()
stream.write('abc')
self.assertEqual(stream.reset_all.called, autoreset)
def testWriteAutoresets(self):
self.assert_autoresets(convert=True)
self.assert_autoresets(convert=False)
self.assert_autoresets(convert=True, autoreset=False)
self.assert_autoresets(convert=False, autoreset=False)
def testWriteAndConvertWritesPlainText(self):
stream = AnsiToWin32(Mock())
stream.write_and_convert( 'abc' )
self.assertEqual( stream.wrapped.write.call_args, (('abc',), {}) )
def testWriteAndConvertStripsAllValidAnsi(self):
stream = AnsiToWin32(Mock())
stream.call_win32 = Mock()
data = [
'abc\033[mdef',
'abc\033[0mdef',
'abc\033[2mdef',
'abc\033[02mdef',
'abc\033[002mdef',
'abc\033[40mdef',
'abc\033[040mdef',
'abc\033[0;1mdef',
'abc\033[40;50mdef',
'abc\033[50;30;40mdef',
'abc\033[Adef',
'abc\033[0Gdef',
'abc\033[1;20;128Hdef',
]
for datum in data:
stream.wrapped.write.reset_mock()
stream.write_and_convert( datum )
self.assertEqual(
[args[0] for args in stream.wrapped.write.call_args_list],
[ ('abc',), ('def',) ]
)
def testWriteAndConvertSkipsEmptySnippets(self):
stream = AnsiToWin32(Mock())
stream.call_win32 = Mock()
stream.write_and_convert( '\033[40m\033[41m' )
self.assertFalse( stream.wrapped.write.called )
def testWriteAndConvertCallsWin32WithParamsAndCommand(self):
stream = AnsiToWin32(Mock())
stream.convert = True
stream.call_win32 = Mock()
stream.extract_params = Mock(return_value='params')
data = {
'abc\033[adef': ('a', 'params'),
'abc\033[;;bdef': ('b', 'params'),
'abc\033[0cdef': ('c', 'params'),
'abc\033[;;0;;Gdef': ('G', 'params'),
'abc\033[1;20;128Hdef': ('H', 'params'),
}
for datum, expected in data.items():
stream.call_win32.reset_mock()
stream.write_and_convert( datum )
self.assertEqual( stream.call_win32.call_args[0], expected )
def test_reset_all_shouldnt_raise_on_closed_orig_stdout(self):
stream = StringIO()
converter = AnsiToWin32(stream)
stream.close()
converter.reset_all()
def test_wrap_shouldnt_raise_on_closed_orig_stdout(self):
stream = StringIO()
stream.close()
with \
patch("colorama.ansitowin32.os.name", "nt"), \
patch("colorama.ansitowin32.winapi_test", lambda: True):
converter = AnsiToWin32(stream)
self.assertTrue(converter.strip)
self.assertFalse(converter.convert)
def test_wrap_shouldnt_raise_on_missing_closed_attr(self):
with \
patch("colorama.ansitowin32.os.name", "nt"), \
patch("colorama.ansitowin32.winapi_test", lambda: True):
converter = AnsiToWin32(object())
self.assertTrue(converter.strip)
self.assertFalse(converter.convert)
def testExtractParams(self):
stream = AnsiToWin32(Mock())
data = {
'': (0,),
';;': (0,),
'2': (2,),
';;002;;': (2,),
'0;1': (0, 1),
';;003;;456;;': (3, 456),
'11;22;33;44;55': (11, 22, 33, 44, 55),
}
for datum, expected in data.items():
self.assertEqual(stream.extract_params('m', datum), expected)
def testCallWin32UsesLookup(self):
listener = Mock()
stream = AnsiToWin32(listener)
stream.win32_calls = {
1: (lambda *_, **__: listener(11),),
2: (lambda *_, **__: listener(22),),
3: (lambda *_, **__: listener(33),),
}
stream.call_win32('m', (3, 1, 99, 2))
self.assertEqual(
[a[0][0] for a in listener.call_args_list],
[33, 11, 22] )
def test_osc_codes(self):
mockStdout = Mock()
stream = AnsiToWin32(mockStdout, convert=True)
with patch('colorama.ansitowin32.winterm') as winterm:
data = [
'\033]0\x07', # missing arguments
'\033]0;foo\x08', # wrong OSC command
'\033]0;colorama_test_title\x07', # should work
'\033]1;colorama_test_title\x07', # wrong set command
'\033]2;colorama_test_title\x07', # should work
'\033]' + ';' * 64 + '\x08', # see issue #247
]
for code in data:
stream.write(code)
self.assertEqual(winterm.set_title.call_count, 2)
def test_native_windows_ansi(self):
with ExitStack() as stack:
def p(a, b):
stack.enter_context(patch(a, b, create=True))
# Pretend to be on Windows
p("colorama.ansitowin32.os.name", "nt")
p("colorama.ansitowin32.winapi_test", lambda: True)
p("colorama.win32.winapi_test", lambda: True)
p("colorama.winterm.win32.windll", "non-None")
p("colorama.winterm.get_osfhandle", lambda _: 1234)
# Pretend that our mock stream has native ANSI support
p(
"colorama.winterm.win32.GetConsoleMode",
lambda _: ENABLE_VIRTUAL_TERMINAL_PROCESSING,
)
SetConsoleMode = Mock()
p("colorama.winterm.win32.SetConsoleMode", SetConsoleMode)
stdout = Mock()
stdout.closed = False
stdout.isatty.return_value = True
stdout.fileno.return_value = 1
# Our fake console says it has native vt support, so AnsiToWin32 should
# enable that support and do nothing else.
stream = AnsiToWin32(stdout)
SetConsoleMode.assert_called_with(1234, ENABLE_VIRTUAL_TERMINAL_PROCESSING)
self.assertFalse(stream.strip)
self.assertFalse(stream.convert)
self.assertFalse(stream.should_wrap())
# Now let's pretend we're on an old Windows console, that doesn't have
# native ANSI support.
p("colorama.winterm.win32.GetConsoleMode", lambda _: 0)
SetConsoleMode = Mock()
p("colorama.winterm.win32.SetConsoleMode", SetConsoleMode)
stream = AnsiToWin32(stdout)
SetConsoleMode.assert_called_with(1234, ENABLE_VIRTUAL_TERMINAL_PROCESSING)
self.assertTrue(stream.strip)
self.assertTrue(stream.convert)
self.assertTrue(stream.should_wrap())
if __name__ == '__main__':
main()

View file

@ -1,189 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import sys
from unittest import TestCase, main, skipUnless
try:
from unittest.mock import patch, Mock
except ImportError:
from mock import patch, Mock
from ..ansitowin32 import StreamWrapper
from ..initialise import init, just_fix_windows_console, _wipe_internal_state_for_tests
from .utils import osname, replace_by
orig_stdout = sys.stdout
orig_stderr = sys.stderr
class InitTest(TestCase):
@skipUnless(sys.stdout.isatty(), "sys.stdout is not a tty")
def setUp(self):
# sanity check
self.assertNotWrapped()
def tearDown(self):
_wipe_internal_state_for_tests()
sys.stdout = orig_stdout
sys.stderr = orig_stderr
def assertWrapped(self):
self.assertIsNot(sys.stdout, orig_stdout, 'stdout should be wrapped')
self.assertIsNot(sys.stderr, orig_stderr, 'stderr should be wrapped')
self.assertTrue(isinstance(sys.stdout, StreamWrapper),
'bad stdout wrapper')
self.assertTrue(isinstance(sys.stderr, StreamWrapper),
'bad stderr wrapper')
def assertNotWrapped(self):
self.assertIs(sys.stdout, orig_stdout, 'stdout should not be wrapped')
self.assertIs(sys.stderr, orig_stderr, 'stderr should not be wrapped')
@patch('colorama.initialise.reset_all')
@patch('colorama.ansitowin32.winapi_test', lambda *_: True)
@patch('colorama.ansitowin32.enable_vt_processing', lambda *_: False)
def testInitWrapsOnWindows(self, _):
with osname("nt"):
init()
self.assertWrapped()
@patch('colorama.initialise.reset_all')
@patch('colorama.ansitowin32.winapi_test', lambda *_: False)
def testInitDoesntWrapOnEmulatedWindows(self, _):
with osname("nt"):
init()
self.assertNotWrapped()
def testInitDoesntWrapOnNonWindows(self):
with osname("posix"):
init()
self.assertNotWrapped()
def testInitDoesntWrapIfNone(self):
with replace_by(None):
init()
# We can't use assertNotWrapped here because replace_by(None)
# changes stdout/stderr already.
self.assertIsNone(sys.stdout)
self.assertIsNone(sys.stderr)
def testInitAutoresetOnWrapsOnAllPlatforms(self):
with osname("posix"):
init(autoreset=True)
self.assertWrapped()
def testInitWrapOffDoesntWrapOnWindows(self):
with osname("nt"):
init(wrap=False)
self.assertNotWrapped()
def testInitWrapOffIncompatibleWithAutoresetOn(self):
self.assertRaises(ValueError, lambda: init(autoreset=True, wrap=False))
@patch('colorama.win32.SetConsoleTextAttribute')
@patch('colorama.initialise.AnsiToWin32')
def testAutoResetPassedOn(self, mockATW32, _):
with osname("nt"):
init(autoreset=True)
self.assertEqual(len(mockATW32.call_args_list), 2)
self.assertEqual(mockATW32.call_args_list[1][1]['autoreset'], True)
self.assertEqual(mockATW32.call_args_list[0][1]['autoreset'], True)
@patch('colorama.initialise.AnsiToWin32')
def testAutoResetChangeable(self, mockATW32):
with osname("nt"):
init()
init(autoreset=True)
self.assertEqual(len(mockATW32.call_args_list), 4)
self.assertEqual(mockATW32.call_args_list[2][1]['autoreset'], True)
self.assertEqual(mockATW32.call_args_list[3][1]['autoreset'], True)
init()
self.assertEqual(len(mockATW32.call_args_list), 6)
self.assertEqual(
mockATW32.call_args_list[4][1]['autoreset'], False)
self.assertEqual(
mockATW32.call_args_list[5][1]['autoreset'], False)
@patch('colorama.initialise.atexit.register')
def testAtexitRegisteredOnlyOnce(self, mockRegister):
init()
self.assertTrue(mockRegister.called)
mockRegister.reset_mock()
init()
self.assertFalse(mockRegister.called)
class JustFixWindowsConsoleTest(TestCase):
def _reset(self):
_wipe_internal_state_for_tests()
sys.stdout = orig_stdout
sys.stderr = orig_stderr
def tearDown(self):
self._reset()
@patch("colorama.ansitowin32.winapi_test", lambda: True)
def testJustFixWindowsConsole(self):
if sys.platform != "win32":
# just_fix_windows_console should be a no-op
just_fix_windows_console()
self.assertIs(sys.stdout, orig_stdout)
self.assertIs(sys.stderr, orig_stderr)
else:
def fake_std():
# Emulate stdout=not a tty, stderr=tty
# to check that we handle both cases correctly
stdout = Mock()
stdout.closed = False
stdout.isatty.return_value = False
stdout.fileno.return_value = 1
sys.stdout = stdout
stderr = Mock()
stderr.closed = False
stderr.isatty.return_value = True
stderr.fileno.return_value = 2
sys.stderr = stderr
for native_ansi in [False, True]:
with patch(
'colorama.ansitowin32.enable_vt_processing',
lambda *_: native_ansi
):
self._reset()
fake_std()
# Regular single-call test
prev_stdout = sys.stdout
prev_stderr = sys.stderr
just_fix_windows_console()
self.assertIs(sys.stdout, prev_stdout)
if native_ansi:
self.assertIs(sys.stderr, prev_stderr)
else:
self.assertIsNot(sys.stderr, prev_stderr)
# second call without resetting is always a no-op
prev_stdout = sys.stdout
prev_stderr = sys.stderr
just_fix_windows_console()
self.assertIs(sys.stdout, prev_stdout)
self.assertIs(sys.stderr, prev_stderr)
self._reset()
fake_std()
# If init() runs first, just_fix_windows_console should be a no-op
init()
prev_stdout = sys.stdout
prev_stderr = sys.stderr
just_fix_windows_console()
self.assertIs(prev_stdout, sys.stdout)
self.assertIs(prev_stderr, sys.stderr)
if __name__ == '__main__':
main()

View file

@ -1,57 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import sys
from unittest import TestCase, main
from ..ansitowin32 import StreamWrapper, AnsiToWin32
from .utils import pycharm, replace_by, replace_original_by, StreamTTY, StreamNonTTY
def is_a_tty(stream):
return StreamWrapper(stream, None).isatty()
class IsattyTest(TestCase):
def test_TTY(self):
tty = StreamTTY()
self.assertTrue(is_a_tty(tty))
with pycharm():
self.assertTrue(is_a_tty(tty))
def test_nonTTY(self):
non_tty = StreamNonTTY()
self.assertFalse(is_a_tty(non_tty))
with pycharm():
self.assertFalse(is_a_tty(non_tty))
def test_withPycharm(self):
with pycharm():
self.assertTrue(is_a_tty(sys.stderr))
self.assertTrue(is_a_tty(sys.stdout))
def test_withPycharmTTYOverride(self):
tty = StreamTTY()
with pycharm(), replace_by(tty):
self.assertTrue(is_a_tty(tty))
def test_withPycharmNonTTYOverride(self):
non_tty = StreamNonTTY()
with pycharm(), replace_by(non_tty):
self.assertFalse(is_a_tty(non_tty))
def test_withPycharmNoneOverride(self):
with pycharm():
with replace_by(None), replace_original_by(None):
self.assertFalse(is_a_tty(None))
self.assertFalse(is_a_tty(StreamNonTTY()))
self.assertTrue(is_a_tty(StreamTTY()))
def test_withPycharmStreamWrapped(self):
with pycharm():
self.assertTrue(AnsiToWin32(StreamTTY()).stream.isatty())
self.assertFalse(AnsiToWin32(StreamNonTTY()).stream.isatty())
self.assertTrue(AnsiToWin32(sys.stdout).stream.isatty())
self.assertTrue(AnsiToWin32(sys.stderr).stream.isatty())
if __name__ == '__main__':
main()

View file

@ -1,49 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
from contextlib import contextmanager
from io import StringIO
import sys
import os
class StreamTTY(StringIO):
def isatty(self):
return True
class StreamNonTTY(StringIO):
def isatty(self):
return False
@contextmanager
def osname(name):
orig = os.name
os.name = name
yield
os.name = orig
@contextmanager
def replace_by(stream):
orig_stdout = sys.stdout
orig_stderr = sys.stderr
sys.stdout = stream
sys.stderr = stream
yield
sys.stdout = orig_stdout
sys.stderr = orig_stderr
@contextmanager
def replace_original_by(stream):
orig_stdout = sys.__stdout__
orig_stderr = sys.__stderr__
sys.__stdout__ = stream
sys.__stderr__ = stream
yield
sys.__stdout__ = orig_stdout
sys.__stderr__ = orig_stderr
@contextmanager
def pycharm():
os.environ["PYCHARM_HOSTED"] = "1"
non_tty = StreamNonTTY()
with replace_by(non_tty), replace_original_by(non_tty):
yield
del os.environ["PYCHARM_HOSTED"]

View file

@ -1,131 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
import sys
from unittest import TestCase, main, skipUnless
try:
from unittest.mock import Mock, patch
except ImportError:
from mock import Mock, patch
from ..winterm import WinColor, WinStyle, WinTerm
class WinTermTest(TestCase):
@patch('colorama.winterm.win32')
def testInit(self, mockWin32):
mockAttr = Mock()
mockAttr.wAttributes = 7 + 6 * 16 + 8
mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr
term = WinTerm()
self.assertEqual(term._fore, 7)
self.assertEqual(term._back, 6)
self.assertEqual(term._style, 8)
@skipUnless(sys.platform.startswith("win"), "requires Windows")
def testGetAttrs(self):
term = WinTerm()
term._fore = 0
term._back = 0
term._style = 0
self.assertEqual(term.get_attrs(), 0)
term._fore = WinColor.YELLOW
self.assertEqual(term.get_attrs(), WinColor.YELLOW)
term._back = WinColor.MAGENTA
self.assertEqual(
term.get_attrs(),
WinColor.YELLOW + WinColor.MAGENTA * 16)
term._style = WinStyle.BRIGHT
self.assertEqual(
term.get_attrs(),
WinColor.YELLOW + WinColor.MAGENTA * 16 + WinStyle.BRIGHT)
@patch('colorama.winterm.win32')
def testResetAll(self, mockWin32):
mockAttr = Mock()
mockAttr.wAttributes = 1 + 2 * 16 + 8
mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr
term = WinTerm()
term.set_console = Mock()
term._fore = -1
term._back = -1
term._style = -1
term.reset_all()
self.assertEqual(term._fore, 1)
self.assertEqual(term._back, 2)
self.assertEqual(term._style, 8)
self.assertEqual(term.set_console.called, True)
@skipUnless(sys.platform.startswith("win"), "requires Windows")
def testFore(self):
term = WinTerm()
term.set_console = Mock()
term._fore = 0
term.fore(5)
self.assertEqual(term._fore, 5)
self.assertEqual(term.set_console.called, True)
@skipUnless(sys.platform.startswith("win"), "requires Windows")
def testBack(self):
term = WinTerm()
term.set_console = Mock()
term._back = 0
term.back(5)
self.assertEqual(term._back, 5)
self.assertEqual(term.set_console.called, True)
@skipUnless(sys.platform.startswith("win"), "requires Windows")
def testStyle(self):
term = WinTerm()
term.set_console = Mock()
term._style = 0
term.style(22)
self.assertEqual(term._style, 22)
self.assertEqual(term.set_console.called, True)
@patch('colorama.winterm.win32')
def testSetConsole(self, mockWin32):
mockAttr = Mock()
mockAttr.wAttributes = 0
mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr
term = WinTerm()
term.windll = Mock()
term.set_console()
self.assertEqual(
mockWin32.SetConsoleTextAttribute.call_args,
((mockWin32.STDOUT, term.get_attrs()), {})
)
@patch('colorama.winterm.win32')
def testSetConsoleOnStderr(self, mockWin32):
mockAttr = Mock()
mockAttr.wAttributes = 0
mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr
term = WinTerm()
term.windll = Mock()
term.set_console(on_stderr=True)
self.assertEqual(
mockWin32.SetConsoleTextAttribute.call_args,
((mockWin32.STDERR, term.get_attrs()), {})
)
if __name__ == '__main__':
main()

View file

@ -1,180 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
# from winbase.h
STDOUT = -11
STDERR = -12
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
try:
import ctypes
from ctypes import LibraryLoader
windll = LibraryLoader(ctypes.WinDLL)
from ctypes import wintypes
except (AttributeError, ImportError):
windll = None
SetConsoleTextAttribute = lambda *_: None
winapi_test = lambda *_: None
else:
from ctypes import byref, Structure, c_char, POINTER
COORD = wintypes._COORD
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
"""struct in wincon.h."""
_fields_ = [
("dwSize", COORD),
("dwCursorPosition", COORD),
("wAttributes", wintypes.WORD),
("srWindow", wintypes.SMALL_RECT),
("dwMaximumWindowSize", COORD),
]
def __str__(self):
return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
self.dwSize.Y, self.dwSize.X
, self.dwCursorPosition.Y, self.dwCursorPosition.X
, self.wAttributes
, self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
, self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
)
_GetStdHandle = windll.kernel32.GetStdHandle
_GetStdHandle.argtypes = [
wintypes.DWORD,
]
_GetStdHandle.restype = wintypes.HANDLE
_GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
_GetConsoleScreenBufferInfo.argtypes = [
wintypes.HANDLE,
POINTER(CONSOLE_SCREEN_BUFFER_INFO),
]
_GetConsoleScreenBufferInfo.restype = wintypes.BOOL
_SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
_SetConsoleTextAttribute.argtypes = [
wintypes.HANDLE,
wintypes.WORD,
]
_SetConsoleTextAttribute.restype = wintypes.BOOL
_SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition
_SetConsoleCursorPosition.argtypes = [
wintypes.HANDLE,
COORD,
]
_SetConsoleCursorPosition.restype = wintypes.BOOL
_FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA
_FillConsoleOutputCharacterA.argtypes = [
wintypes.HANDLE,
c_char,
wintypes.DWORD,
COORD,
POINTER(wintypes.DWORD),
]
_FillConsoleOutputCharacterA.restype = wintypes.BOOL
_FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute
_FillConsoleOutputAttribute.argtypes = [
wintypes.HANDLE,
wintypes.WORD,
wintypes.DWORD,
COORD,
POINTER(wintypes.DWORD),
]
_FillConsoleOutputAttribute.restype = wintypes.BOOL
_SetConsoleTitleW = windll.kernel32.SetConsoleTitleW
_SetConsoleTitleW.argtypes = [
wintypes.LPCWSTR
]
_SetConsoleTitleW.restype = wintypes.BOOL
_GetConsoleMode = windll.kernel32.GetConsoleMode
_GetConsoleMode.argtypes = [
wintypes.HANDLE,
POINTER(wintypes.DWORD)
]
_GetConsoleMode.restype = wintypes.BOOL
_SetConsoleMode = windll.kernel32.SetConsoleMode
_SetConsoleMode.argtypes = [
wintypes.HANDLE,
wintypes.DWORD
]
_SetConsoleMode.restype = wintypes.BOOL
def _winapi_test(handle):
csbi = CONSOLE_SCREEN_BUFFER_INFO()
success = _GetConsoleScreenBufferInfo(
handle, byref(csbi))
return bool(success)
def winapi_test():
return any(_winapi_test(h) for h in
(_GetStdHandle(STDOUT), _GetStdHandle(STDERR)))
def GetConsoleScreenBufferInfo(stream_id=STDOUT):
handle = _GetStdHandle(stream_id)
csbi = CONSOLE_SCREEN_BUFFER_INFO()
success = _GetConsoleScreenBufferInfo(
handle, byref(csbi))
return csbi
def SetConsoleTextAttribute(stream_id, attrs):
handle = _GetStdHandle(stream_id)
return _SetConsoleTextAttribute(handle, attrs)
def SetConsoleCursorPosition(stream_id, position, adjust=True):
position = COORD(*position)
# If the position is out of range, do nothing.
if position.Y <= 0 or position.X <= 0:
return
# Adjust for Windows' SetConsoleCursorPosition:
# 1. being 0-based, while ANSI is 1-based.
# 2. expecting (x,y), while ANSI uses (y,x).
adjusted_position = COORD(position.Y - 1, position.X - 1)
if adjust:
# Adjust for viewport's scroll position
sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
adjusted_position.Y += sr.Top
adjusted_position.X += sr.Left
# Resume normal processing
handle = _GetStdHandle(stream_id)
return _SetConsoleCursorPosition(handle, adjusted_position)
def FillConsoleOutputCharacter(stream_id, char, length, start):
handle = _GetStdHandle(stream_id)
char = c_char(char.encode())
length = wintypes.DWORD(length)
num_written = wintypes.DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
success = _FillConsoleOutputCharacterA(
handle, char, length, start, byref(num_written))
return num_written.value
def FillConsoleOutputAttribute(stream_id, attr, length, start):
''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
handle = _GetStdHandle(stream_id)
attribute = wintypes.WORD(attr)
length = wintypes.DWORD(length)
num_written = wintypes.DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
return _FillConsoleOutputAttribute(
handle, attribute, length, start, byref(num_written))
def SetConsoleTitle(title):
return _SetConsoleTitleW(title)
def GetConsoleMode(handle):
mode = wintypes.DWORD()
success = _GetConsoleMode(handle, byref(mode))
if not success:
raise ctypes.WinError()
return mode.value
def SetConsoleMode(handle, mode):
success = _SetConsoleMode(handle, mode)
if not success:
raise ctypes.WinError()

View file

@ -1,195 +0,0 @@
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
try:
from msvcrt import get_osfhandle
except ImportError:
def get_osfhandle(_):
raise OSError("This isn't windows!")
from . import win32
# from wincon.h
class WinColor(object):
BLACK = 0
BLUE = 1
GREEN = 2
CYAN = 3
RED = 4
MAGENTA = 5
YELLOW = 6
GREY = 7
# from wincon.h
class WinStyle(object):
NORMAL = 0x00 # dim text, dim background
BRIGHT = 0x08 # bright text, dim background
BRIGHT_BACKGROUND = 0x80 # dim text, bright background
class WinTerm(object):
def __init__(self):
self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes
self.set_attrs(self._default)
self._default_fore = self._fore
self._default_back = self._back
self._default_style = self._style
# In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style.
# So that LIGHT_EX colors and BRIGHT style do not clobber each other,
# we track them separately, since LIGHT_EX is overwritten by Fore/Back
# and BRIGHT is overwritten by Style codes.
self._light = 0
def get_attrs(self):
return self._fore + self._back * 16 + (self._style | self._light)
def set_attrs(self, value):
self._fore = value & 7
self._back = (value >> 4) & 7
self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND)
def reset_all(self, on_stderr=None):
self.set_attrs(self._default)
self.set_console(attrs=self._default)
self._light = 0
def fore(self, fore=None, light=False, on_stderr=False):
if fore is None:
fore = self._default_fore
self._fore = fore
# Emulate LIGHT_EX with BRIGHT Style
if light:
self._light |= WinStyle.BRIGHT
else:
self._light &= ~WinStyle.BRIGHT
self.set_console(on_stderr=on_stderr)
def back(self, back=None, light=False, on_stderr=False):
if back is None:
back = self._default_back
self._back = back
# Emulate LIGHT_EX with BRIGHT_BACKGROUND Style
if light:
self._light |= WinStyle.BRIGHT_BACKGROUND
else:
self._light &= ~WinStyle.BRIGHT_BACKGROUND
self.set_console(on_stderr=on_stderr)
def style(self, style=None, on_stderr=False):
if style is None:
style = self._default_style
self._style = style
self.set_console(on_stderr=on_stderr)
def set_console(self, attrs=None, on_stderr=False):
if attrs is None:
attrs = self.get_attrs()
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
win32.SetConsoleTextAttribute(handle, attrs)
def get_position(self, handle):
position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition
# Because Windows coordinates are 0-based,
# and win32.SetConsoleCursorPosition expects 1-based.
position.X += 1
position.Y += 1
return position
def set_cursor_position(self, position=None, on_stderr=False):
if position is None:
# I'm not currently tracking the position, so there is no default.
# position = self.get_position()
return
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
win32.SetConsoleCursorPosition(handle, position)
def cursor_adjust(self, x, y, on_stderr=False):
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
position = self.get_position(handle)
adjusted_position = (position.Y + y, position.X + x)
win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False)
def erase_screen(self, mode=0, on_stderr=False):
# 0 should clear from the cursor to the end of the screen.
# 1 should clear from the cursor to the beginning of the screen.
# 2 should clear the entire screen, and move cursor to (1,1)
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
csbi = win32.GetConsoleScreenBufferInfo(handle)
# get the number of character cells in the current buffer
cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y
# get number of character cells before current cursor position
cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X
if mode == 0:
from_coord = csbi.dwCursorPosition
cells_to_erase = cells_in_screen - cells_before_cursor
elif mode == 1:
from_coord = win32.COORD(0, 0)
cells_to_erase = cells_before_cursor
elif mode == 2:
from_coord = win32.COORD(0, 0)
cells_to_erase = cells_in_screen
else:
# invalid mode
return
# fill the entire screen with blanks
win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord)
# now set the buffer's attributes accordingly
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord)
if mode == 2:
# put the cursor where needed
win32.SetConsoleCursorPosition(handle, (1, 1))
def erase_line(self, mode=0, on_stderr=False):
# 0 should clear from the cursor to the end of the line.
# 1 should clear from the cursor to the beginning of the line.
# 2 should clear the entire line.
handle = win32.STDOUT
if on_stderr:
handle = win32.STDERR
csbi = win32.GetConsoleScreenBufferInfo(handle)
if mode == 0:
from_coord = csbi.dwCursorPosition
cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X
elif mode == 1:
from_coord = win32.COORD(0, csbi.dwCursorPosition.Y)
cells_to_erase = csbi.dwCursorPosition.X
elif mode == 2:
from_coord = win32.COORD(0, csbi.dwCursorPosition.Y)
cells_to_erase = csbi.dwSize.X
else:
# invalid mode
return
# fill the entire screen with blanks
win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord)
# now set the buffer's attributes accordingly
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord)
def set_title(self, title):
win32.SetConsoleTitle(title)
def enable_vt_processing(fd):
if win32.windll is None or not win32.winapi_test():
return False
try:
handle = get_osfhandle(fd)
mode = win32.GetConsoleMode(handle)
win32.SetConsoleMode(
handle,
mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING,
)
mode = win32.GetConsoleMode(handle)
if mode & win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING:
return True
# Can get TypeError in testsuite where 'fd' is a Mock()
except (OSError, TypeError):
return False

View file

@ -1 +0,0 @@
import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'local') == 'local'; enabled and __import__('_distutils_hack').add_shim();

View file

@ -1,51 +0,0 @@
Original Authors
----------------
* Armin Rigo
* Christian Tismer
Contributors
------------
* Al Stone
* Alexander Schmidt
* Alexey Borzenkov
* Andreas Schwab
* Armin Ronacher
* Bin Wang <feisuzhu@163.com>
* Bob Ippolito
* ChangBo Guo
* Christoph Gohlke
* Denis Bilenko
* Dirk Mueller
* Donovan Preston
* Fantix King
* Floris Bruynooghe
* Fredrik Fornwall
* Gerd Woetzel
* Giel van Schijndel
* Gökhan Karabulut
* Gustavo Niemeyer
* Guy Rozendorn
* Hye-Shik Chang
* Jared Kuolt
* Jason Madden
* Josh Snyder
* Kyle Ambroff
* Laszlo Boszormenyi
* Mao Han
* Marc Abramowitz
* Marc Schlaich
* Marcin Bachry
* Matt Madison
* Matt Turner
* Michael Ellerman
* Michael Matz
* Ralf Schmitt
* Robie Basak
* Ronny Pfannschmidt
* Samual M. Rushing
* Tony Bowles
* Tony Breeds
* Trevor Bowen
* Tulio Magno Quites Machado Filho
* Ulrich Weigand
* Victor Stinner

View file

@ -1,30 +0,0 @@
The following files are derived from Stackless Python and are subject to the
same license as Stackless Python:
src/greenlet/slp_platformselect.h
files in src/greenlet/platform/ directory
See LICENSE.PSF and http://www.stackless.com/ for details.
Unless otherwise noted, the files in greenlet have been released under the
following MIT license:
Copyright (c) Armin Rigo, Christian Tismer and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,47 +0,0 @@
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011 Python Software Foundation; All Rights Reserved" are retained in Python
alone or in any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.
4. PSF is making Python available to Licensee on an "AS IS"
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee. This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.

View file

@ -1,102 +0,0 @@
Metadata-Version: 2.1
Name: greenlet
Version: 3.0.3
Summary: Lightweight in-process concurrent programming
Home-page: https://greenlet.readthedocs.io/
Author: Alexey Borzenkov
Author-email: snaury@gmail.com
Maintainer: Jason Madden
Maintainer-email: jason@seecoresoftware.com
License: MIT License
Project-URL: Bug Tracker, https://github.com/python-greenlet/greenlet/issues
Project-URL: Source Code, https://github.com/python-greenlet/greenlet/
Project-URL: Documentation, https://greenlet.readthedocs.io/
Keywords: greenlet coroutine concurrency threads cooperative
Platform: any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Programming Language :: C
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE
License-File: LICENSE.PSF
License-File: AUTHORS
Provides-Extra: docs
Requires-Dist: Sphinx ; extra == 'docs'
Requires-Dist: furo ; extra == 'docs'
Provides-Extra: test
Requires-Dist: objgraph ; extra == 'test'
Requires-Dist: psutil ; extra == 'test'
.. This file is included into docs/history.rst
Greenlets are lightweight coroutines for in-process concurrent
programming.
The "greenlet" package is a spin-off of `Stackless`_, a version of
CPython that supports micro-threads called "tasklets". Tasklets run
pseudo-concurrently (typically in a single or a few OS-level threads)
and are synchronized with data exchanges on "channels".
A "greenlet", on the other hand, is a still more primitive notion of
micro-thread with no implicit scheduling; coroutines, in other words.
This is useful when you want to control exactly when your code runs.
You can build custom scheduled micro-threads on top of greenlet;
however, it seems that greenlets are useful on their own as a way to
make advanced control flow structures. For example, we can recreate
generators; the difference with Python's own generators is that our
generators can call nested functions and the nested functions can
yield values too. (Additionally, you don't need a "yield" keyword. See
the example in `test_generator.py
<https://github.com/python-greenlet/greenlet/blob/adca19bf1f287b3395896a8f41f3f4fd1797fdc7/src/greenlet/tests/test_generator.py#L1>`_).
Greenlets are provided as a C extension module for the regular unmodified
interpreter.
.. _`Stackless`: http://www.stackless.com
Who is using Greenlet?
======================
There are several libraries that use Greenlet as a more flexible
alternative to Python's built in coroutine support:
- `Concurrence`_
- `Eventlet`_
- `Gevent`_
.. _Concurrence: http://opensource.hyves.org/concurrence/
.. _Eventlet: http://eventlet.net/
.. _Gevent: http://www.gevent.org/
Getting Greenlet
================
The easiest way to get Greenlet is to install it with pip::
pip install greenlet
Source code archives and binary distributions are available on the
python package index at https://pypi.org/project/greenlet
The source code repository is hosted on github:
https://github.com/python-greenlet/greenlet
Documentation is available on readthedocs.org:
https://greenlet.readthedocs.io

View file

@ -1,117 +0,0 @@
../../../include/site/python3.11/greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755
greenlet-3.0.3.dist-info/AUTHORS,sha256=swW28t2knVRxRkaEQNZtO7MP9Sgnompb7B6cNgJM8Gk,849
greenlet-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
greenlet-3.0.3.dist-info/LICENSE,sha256=dpgx1uXfrywggC-sz_H6-0wgJd2PYlPfpH_K1Z1NCXk,1434
greenlet-3.0.3.dist-info/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424
greenlet-3.0.3.dist-info/METADATA,sha256=CHtHlitUM_AS9hKoJfYLF3Vz-UFJlqRnhbRl2-1JrjU,3779
greenlet-3.0.3.dist-info/RECORD,,
greenlet-3.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
greenlet-3.0.3.dist-info/WHEEL,sha256=xlJUan517virathN2lKmlOcMObJx20JZaCR_iv23glU,153
greenlet-3.0.3.dist-info/top_level.txt,sha256=YSnRsCRoO61JGlP57o8iKL6rdLWDWuiyKD8ekpWUsDc,9
greenlet/TBrokenGreenlet.cpp,sha256=YgKaHkQV6_dKBrgS0HKDSqZroskv0IwSZDo4bsiwz3w,1029
greenlet/TExceptionState.cpp,sha256=Ctg2YfyEYNjOYbteRB_oIJa9lNGyC7N1F3h4XqqQdg8,1367
greenlet/TGreenlet.cpp,sha256=1xwAzGNqO68AZ4D5lD5DHmGPBohM6nv4BYnLatgIL68,25637
greenlet/TGreenletGlobals.cpp,sha256=qLi1icS1UDSbefTkolz9TycEi_GOUblsEznMp0HFywQ,3268
greenlet/TMainGreenlet.cpp,sha256=FvWtGJDKb64DLy0n-ddcTF6xJDwczPMKSm9mXSsHJKg,3365
greenlet/TPythonState.cpp,sha256=QUoIQzF0HYmAJO_nwX5gXSSlMNL1mkxlN24KJCXIrIQ,14861
greenlet/TStackState.cpp,sha256=VclDR-qiMeJjuiJxL9_u24MJiTgdSaYvr8bWQdTEZjY,7389
greenlet/TThreadStateDestroy.cpp,sha256=EqZ-GjksrWNC20CY_P0yXN43wVRMYEh659SmRRqBaI4,7214
greenlet/TUserGreenlet.cpp,sha256=b_Bmh4WZdS6I1yM2AfHRtd535WovtpYMkpfu2GQpaDs,23618
greenlet/__init__.py,sha256=Dw4tovn18bpPaWQ4SK7jDJe24uV4ao264UfaT0uufxU,1723
greenlet/__pycache__/__init__.cpython-311.pyc,,
greenlet/_greenlet.cpython-311-x86_64-linux-gnu.so,sha256=89kThwDfvkHXs3GXeuXnnZb-wShF60h1XyHXZYmkymU,1506232
greenlet/greenlet.cpp,sha256=k9RZolayY79WgjPXwcA3Vcv48MuW7TAtogIZPaDD3gM,48815
greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755
greenlet/greenlet_allocator.hpp,sha256=kxyWW4Qdwlrc7ufgdb5vd6Y7jhauQ699Kod0mqiO1iM,1582
greenlet/greenlet_compiler_compat.hpp,sha256=m7wvwrZqBoCQpDMTP-Z7whdXIES7e3AuXBgvPHSsfxg,4140
greenlet/greenlet_cpython_add_pending.hpp,sha256=apAwIhGlgYrnYn03zWL6Sxy68kltDeb1e0QupZfb3DQ,6043
greenlet/greenlet_cpython_compat.hpp,sha256=ZpN8gewZeOtd6T-mLidA7zteQ_P4vG8T1za_KPvCijg,3621
greenlet/greenlet_exceptions.hpp,sha256=Dt8YdaQn8AK9nBfwU9rrDoMlR2Lw5aLTQV6ZAsHmfsw,3683
greenlet/greenlet_greenlet.hpp,sha256=Ct_EAx4OJL6FvF5g3jV1ybSxnqzLVaRdPi2EcYT1iq4,27728
greenlet/greenlet_internal.hpp,sha256=ZXH5zemWCN8wH8zAqMUGycvz_3IulRL6Gf2hZA6CknE,2703
greenlet/greenlet_refs.hpp,sha256=ECkHKV1CVamtzmWWGKXXMpw8lXLeIzastXM9tfqlsNI,33864
greenlet/greenlet_slp_switch.hpp,sha256=kM1QHA2iV-gH4cFyN6lfIagHQxvJZjWOVJdIxRE3TlQ,3198
greenlet/greenlet_thread_state.hpp,sha256=0UwJCNd86ifwM2yDd3QrNmHAECL-eNADHubwiB_XGA4,20614
greenlet/greenlet_thread_state_dict_cleanup.hpp,sha256=tEN0rI1pZiEsdtr7Oda24gr52fGiHnYTLyM8Vme3Gns,3831
greenlet/greenlet_thread_support.hpp,sha256=XUJ6ljWjf9OYyuOILiz8e_yHvT3fbaUiHdhiPNQUV4s,867
greenlet/platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
greenlet/platform/__pycache__/__init__.cpython-311.pyc,,
greenlet/platform/setup_switch_x64_masm.cmd,sha256=ZpClUJeU0ujEPSTWNSepP0W2f9XiYQKA8QKSoVou8EU,143
greenlet/platform/switch_aarch64_gcc.h,sha256=GKC0yWNXnbK2X--X6aguRCMj2Tg7hDU1Zkl3RljDvC8,4307
greenlet/platform/switch_alpha_unix.h,sha256=Z-SvF8JQV3oxWT8JRbL9RFu4gRFxPdJ7cviM8YayMmw,671
greenlet/platform/switch_amd64_unix.h,sha256=EcSFCBlodEBhqhKjcJqY_5Dn_jn7pKpkJlOvp7gFXLI,2748
greenlet/platform/switch_arm32_gcc.h,sha256=Z3KkHszdgq6uU4YN3BxvKMG2AdDnovwCCNrqGWZ1Lyo,2479
greenlet/platform/switch_arm32_ios.h,sha256=mm5_R9aXB92hyxzFRwB71M60H6AlvHjrpTrc72Pz3l8,1892
greenlet/platform/switch_arm64_masm.asm,sha256=4kpTtfy7rfcr8j1CpJLAK21EtZpGDAJXWRU68HEy5A8,1245
greenlet/platform/switch_arm64_masm.obj,sha256=DmLnIB_icoEHAz1naue_pJPTZgR9ElM7-Nmztr-o9_U,746
greenlet/platform/switch_arm64_msvc.h,sha256=RqK5MHLmXI3Q-FQ7tm32KWnbDNZKnkJdq8CR89cz640,398
greenlet/platform/switch_csky_gcc.h,sha256=kDikyiPpewP71KoBZQO_MukDTXTXBiC7x-hF0_2DL0w,1331
greenlet/platform/switch_loongarch64_linux.h,sha256=7M-Dhc4Q8tRbJCJhalDLwU6S9Mx8MjmN1RbTDgIvQTM,779
greenlet/platform/switch_m68k_gcc.h,sha256=VSa6NpZhvyyvF-Q58CTIWSpEDo4FKygOyTz00whctlw,928
greenlet/platform/switch_mips_unix.h,sha256=E0tYsqc5anDY1BhenU1l8DW-nVHC_BElzLgJw3TGtPk,1426
greenlet/platform/switch_ppc64_aix.h,sha256=_BL0iyRr3ZA5iPlr3uk9SJ5sNRWGYLrXcZ5z-CE9anE,3860
greenlet/platform/switch_ppc64_linux.h,sha256=0rriT5XyxPb0GqsSSn_bP9iQsnjsPbBmu0yqo5goSyQ,3815
greenlet/platform/switch_ppc_aix.h,sha256=pHA4slEjUFP3J3SYm1TAlNPhgb2G_PAtax5cO8BEe1A,2941
greenlet/platform/switch_ppc_linux.h,sha256=YwrlKUzxlXuiKMQqr6MFAV1bPzWnmvk6X1AqJZEpOWU,2759
greenlet/platform/switch_ppc_macosx.h,sha256=L8sB0c00V4G2_5cQCG3zX-23DKq3le_Dcj0sUDcACos,2624
greenlet/platform/switch_ppc_unix.h,sha256=POy4bRBcH74Chfw4viFE9bVlZ-7BaNsFC0NnXr1L2tg,2652
greenlet/platform/switch_riscv_unix.h,sha256=jX3vC_xZXiUho8tz4J6Ai8BNQB80yLn03fxkoMztVCU,740
greenlet/platform/switch_s390_unix.h,sha256=RRlGu957ybmq95qNNY4Qw1mcaoT3eBnW5KbVwu48KX8,2763
greenlet/platform/switch_sparc_sun_gcc.h,sha256=xZish9GsMHBienUbUMsX1-ZZ-as7hs36sVhYIE3ew8Y,2797
greenlet/platform/switch_x32_unix.h,sha256=nM98PKtzTWc1lcM7TRMUZJzskVdR1C69U1UqZRWX0GE,1509
greenlet/platform/switch_x64_masm.asm,sha256=nu6n2sWyXuXfpPx40d9YmLfHXUc1sHgeTvX1kUzuvEM,1841
greenlet/platform/switch_x64_masm.obj,sha256=GNtTNxYdo7idFUYsQv-mrXWgyT5EJ93-9q90lN6svtQ,1078
greenlet/platform/switch_x64_msvc.h,sha256=LIeasyKo_vHzspdMzMHbosRhrBfKI4BkQOh4qcTHyJw,1805
greenlet/platform/switch_x86_msvc.h,sha256=TtGOwinbFfnn6clxMNkCz8i6OmgB6kVRrShoF5iT9to,12838
greenlet/platform/switch_x86_unix.h,sha256=VplW9H0FF0cZHw1DhJdIUs5q6YLS4cwb2nYwjF83R1s,3059
greenlet/slp_platformselect.h,sha256=JEnia_2HsTwdqvnnEsDxHQqalYvFJqx_CDsqvNUQYe8,3600
greenlet/tests/__init__.py,sha256=F282jaIavKrhsYgHJEXtIQXKHdHpe9OJOPTK7R40JzI,9022
greenlet/tests/__pycache__/__init__.cpython-311.pyc,,
greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pyc,,
greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pyc,,
greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pyc,,
greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pyc,,
greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pyc,,
greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pyc,,
greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pyc,,
greenlet/tests/__pycache__/leakcheck.cpython-311.pyc,,
greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc,,
greenlet/tests/__pycache__/test_cpp.cpython-311.pyc,,
greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc,,
greenlet/tests/__pycache__/test_gc.cpython-311.pyc,,
greenlet/tests/__pycache__/test_generator.cpython-311.pyc,,
greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc,,
greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc,,
greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc,,
greenlet/tests/__pycache__/test_leaks.cpython-311.pyc,,
greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc,,
greenlet/tests/__pycache__/test_throw.cpython-311.pyc,,
greenlet/tests/__pycache__/test_tracing.cpython-311.pyc,,
greenlet/tests/__pycache__/test_version.cpython-311.pyc,,
greenlet/tests/__pycache__/test_weakref.cpython-311.pyc,,
greenlet/tests/_test_extension.c,sha256=vkeGA-6oeJcGILsD7oIrT1qZop2GaTOHXiNT7mcSl-0,5773
greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so,sha256=cYvKKnDFhjTDjM_mYc_4l53g44Iz-CJR5woKXR6Ddqg,36624
greenlet/tests/_test_extension_cpp.cpp,sha256=e0kVnaB8CCaEhE9yHtNyfqTjevsPDKKx-zgxk7PPK48,6565
greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so,sha256=de1fYlFMrBJRAwPKHWl-OMuBy8AmSXsh14FYYyLj6dI,57288
greenlet/tests/fail_clearing_run_switches.py,sha256=o433oA_nUCtOPaMEGc8VEhZIKa71imVHXFw7TsXaP8M,1263
greenlet/tests/fail_cpp_exception.py,sha256=o_ZbipWikok8Bjc-vjiQvcb5FHh2nVW-McGKMLcMzh0,985
greenlet/tests/fail_initialstub_already_started.py,sha256=txENn5IyzGx2p-XR1XB7qXmC8JX_4mKDEA8kYBXUQKc,1961
greenlet/tests/fail_slp_switch.py,sha256=rJBZcZfTWR3e2ERQtPAud6YKShiDsP84PmwOJbp4ey0,524
greenlet/tests/fail_switch_three_greenlets.py,sha256=zSitV7rkNnaoHYVzAGGLnxz-yPtohXJJzaE8ehFDQ0M,956
greenlet/tests/fail_switch_three_greenlets2.py,sha256=FPJensn2EJxoropl03JSTVP3kgP33k04h6aDWWozrOk,1285
greenlet/tests/fail_switch_two_greenlets.py,sha256=1CaI8s3504VbbF1vj1uBYuy-zxBHVzHPIAd1LIc8ONg,817
greenlet/tests/leakcheck.py,sha256=inbfM7_oVzd8jIKGxCgo4JqpFZaDAnWPkSULJ8vIE1s,11964
greenlet/tests/test_contextvars.py,sha256=0n5pR_lbpAppc5wFfK0e1SwYLM-fsSFp72B5_ArLPGE,10348
greenlet/tests/test_cpp.py,sha256=hpxhFAdKJTpAVZP8CBGs1ZcrKdscI9BaDZk4btkI5d4,2736
greenlet/tests/test_extension_interface.py,sha256=eJ3cwLacdK2WbsrC-4DgeyHdwLRcG4zx7rrkRtqSzC4,3829
greenlet/tests/test_gc.py,sha256=PCOaRpIyjNnNlDogGL3FZU_lrdXuM-pv1rxeE5TP5mc,2923
greenlet/tests/test_generator.py,sha256=tONXiTf98VGm347o1b-810daPiwdla5cbpFg6QI1R1g,1240
greenlet/tests/test_generator_nested.py,sha256=7v4HOYrf1XZP39dk5IUMubdZ8yc3ynwZcqj9GUJyMSA,3718
greenlet/tests/test_greenlet.py,sha256=95qgDR-xtB0jzEFLirNx7HPUdwHikVMvDdyUoCvyjOo,45354
greenlet/tests/test_greenlet_trash.py,sha256=P6r-3K4fmXX8foW8BVgthuqVKjicHMDvxfK7Al4x028,7508
greenlet/tests/test_leaks.py,sha256=wskLqCAvqZ3qTZkam_wXzd-E5zelUjlXS5Ss8KshtZY,17465
greenlet/tests/test_stack_saved.py,sha256=eyzqNY2VCGuGlxhT_In6TvZ6Okb0AXFZVyBEnK1jDwA,446
greenlet/tests/test_throw.py,sha256=u2TQ_WvvCd6N6JdXWIxVEcXkKu5fepDlz9dktYdmtng,3712
greenlet/tests/test_tracing.py,sha256=VlwzMU0C1noospZhuUMyB7MHw200emIvGCN_6G2p2ZU,8250
greenlet/tests/test_version.py,sha256=O9DpAITsOFgiRcjd4odQ7ejmwx_N9Q1zQENVcbtFHIc,1339
greenlet/tests/test_weakref.py,sha256=F8M23btEF87bIbpptLNBORosbQqNZGiYeKMqYjWrsak,883

View file

@ -1,6 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.42.0)
Root-Is-Purelib: false
Tag: cp311-cp311-manylinux_2_24_x86_64
Tag: cp311-cp311-manylinux_2_28_x86_64

View file

@ -1,45 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/**
* Implementation of greenlet::UserGreenlet.
*
* Format with:
* clang-format -i --style=file src/greenlet/greenlet.c
*
*
* Fix missing braces with:
* clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements"
*/
#include "greenlet_greenlet.hpp"
namespace greenlet {
void* BrokenGreenlet::operator new(size_t UNUSED(count))
{
return allocator.allocate(1);
}
void BrokenGreenlet::operator delete(void* ptr)
{
return allocator.deallocate(static_cast<BrokenGreenlet*>(ptr),
1);
}
greenlet::PythonAllocator<greenlet::BrokenGreenlet> greenlet::BrokenGreenlet::allocator;
bool
BrokenGreenlet::force_slp_switch_error() const noexcept
{
return this->_force_slp_switch_error;
}
UserGreenlet::switchstack_result_t BrokenGreenlet::g_switchstack(void)
{
if (this->_force_switch_error) {
return switchstack_result_t(-1);
}
return UserGreenlet::g_switchstack();
}
}; //namespace greenlet

View file

@ -1,62 +0,0 @@
#ifndef GREENLET_EXCEPTION_STATE_CPP
#define GREENLET_EXCEPTION_STATE_CPP
#include <Python.h>
#include "greenlet_greenlet.hpp"
namespace greenlet {
ExceptionState::ExceptionState()
{
this->clear();
}
void ExceptionState::operator<<(const PyThreadState *const tstate) noexcept
{
this->exc_info = tstate->exc_info;
this->exc_state = tstate->exc_state;
}
void ExceptionState::operator>>(PyThreadState *const tstate) noexcept
{
tstate->exc_state = this->exc_state;
tstate->exc_info =
this->exc_info ? this->exc_info : &tstate->exc_state;
this->clear();
}
void ExceptionState::clear() noexcept
{
this->exc_info = nullptr;
this->exc_state.exc_value = nullptr;
#if !GREENLET_PY311
this->exc_state.exc_type = nullptr;
this->exc_state.exc_traceback = nullptr;
#endif
this->exc_state.previous_item = nullptr;
}
int ExceptionState::tp_traverse(visitproc visit, void* arg) noexcept
{
Py_VISIT(this->exc_state.exc_value);
#if !GREENLET_PY311
Py_VISIT(this->exc_state.exc_type);
Py_VISIT(this->exc_state.exc_traceback);
#endif
return 0;
}
void ExceptionState::tp_clear() noexcept
{
Py_CLEAR(this->exc_state.exc_value);
#if !GREENLET_PY311
Py_CLEAR(this->exc_state.exc_type);
Py_CLEAR(this->exc_state.exc_traceback);
#endif
}
}; // namespace greenlet
#endif // GREENLET_EXCEPTION_STATE_CPP

View file

@ -1,714 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/**
* Implementation of greenlet::Greenlet.
*
* Format with:
* clang-format -i --style=file src/greenlet/greenlet.c
*
*
* Fix missing braces with:
* clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements"
*/
#include "greenlet_internal.hpp"
#include "greenlet_greenlet.hpp"
#include "greenlet_thread_state.hpp"
#include "TGreenletGlobals.cpp"
#include "TThreadStateDestroy.cpp"
namespace greenlet {
Greenlet::Greenlet(PyGreenlet* p)
{
p ->pimpl = this;
}
Greenlet::~Greenlet()
{
// XXX: Can't do this. tp_clear is a virtual function, and by the
// time we're here, we've sliced off our child classes.
//this->tp_clear();
}
Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack)
: stack_state(initial_stack)
{
// can't use a delegating constructor because of
// MSVC for Python 2.7
p->pimpl = this;
}
bool
Greenlet::force_slp_switch_error() const noexcept
{
return false;
}
void
Greenlet::release_args()
{
this->switch_args.CLEAR();
}
/**
* CAUTION: This will allocate memory and may trigger garbage
* collection and arbitrary Python code.
*/
OwnedObject
Greenlet::throw_GreenletExit_during_dealloc(const ThreadState& UNUSED(current_thread_state))
{
// If we're killed because we lost all references in the
// middle of a switch, that's ok. Don't reset the args/kwargs,
// we still want to pass them to the parent.
PyErr_SetString(mod_globs->PyExc_GreenletExit,
"Killing the greenlet because all references have vanished.");
// To get here it had to have run before
return this->g_switch();
}
inline void
Greenlet::slp_restore_state() noexcept
{
#ifdef SLP_BEFORE_RESTORE_STATE
SLP_BEFORE_RESTORE_STATE();
#endif
this->stack_state.copy_heap_to_stack(
this->thread_state()->borrow_current()->stack_state);
}
inline int
Greenlet::slp_save_state(char *const stackref) noexcept
{
// XXX: This used to happen in the middle, before saving, but
// after finding the next owner. Does that matter? This is
// only defined for Sparc/GCC where it flushes register
// windows to the stack (I think)
#ifdef SLP_BEFORE_SAVE_STATE
SLP_BEFORE_SAVE_STATE();
#endif
return this->stack_state.copy_stack_to_heap(stackref,
this->thread_state()->borrow_current()->stack_state);
}
/**
* CAUTION: This will allocate memory and may trigger garbage
* collection and arbitrary Python code.
*/
OwnedObject
Greenlet::on_switchstack_or_initialstub_failure(
Greenlet* target,
const Greenlet::switchstack_result_t& err,
const bool target_was_me,
const bool was_initial_stub)
{
// If we get here, either g_initialstub()
// failed, or g_switchstack() failed. Either one of those
// cases SHOULD leave us in the original greenlet with a valid stack.
if (!PyErr_Occurred()) {
PyErr_SetString(
PyExc_SystemError,
was_initial_stub
? "Failed to switch stacks into a greenlet for the first time."
: "Failed to switch stacks into a running greenlet.");
}
this->release_args();
if (target && !target_was_me) {
target->murder_in_place();
}
assert(!err.the_new_current_greenlet);
assert(!err.origin_greenlet);
return OwnedObject();
}
OwnedGreenlet
Greenlet::g_switchstack_success() noexcept
{
PyThreadState* tstate = PyThreadState_GET();
// restore the saved state
this->python_state >> tstate;
this->exception_state >> tstate;
// The thread state hasn't been changed yet.
ThreadState* thread_state = this->thread_state();
OwnedGreenlet result(thread_state->get_current());
thread_state->set_current(this->self());
//assert(thread_state->borrow_current().borrow() == this->_self);
return result;
}
Greenlet::switchstack_result_t
Greenlet::g_switchstack(void)
{
// if any of these assertions fail, it's likely because we
// switched away and tried to switch back to us. Early stages of
// switching are not reentrant because we re-use ``this->args()``.
// Switching away would happen if we trigger a garbage collection
// (by just using some Python APIs that happen to allocate Python
// objects) and some garbage had weakref callbacks or __del__ that
// switches (people don't write code like that by hand, but with
// gevent it's possible without realizing it)
assert(this->args() || PyErr_Occurred());
{ /* save state */
if (this->thread_state()->is_current(this->self())) {
// Hmm, nothing to do.
// TODO: Does this bypass trace events that are
// important?
return switchstack_result_t(0,
this, this->thread_state()->borrow_current());
}
BorrowedGreenlet current = this->thread_state()->borrow_current();
PyThreadState* tstate = PyThreadState_GET();
current->python_state << tstate;
current->exception_state << tstate;
this->python_state.will_switch_from(tstate);
switching_thread_state = this;
current->expose_frames();
}
assert(this->args() || PyErr_Occurred());
// If this is the first switch into a greenlet, this will
// return twice, once with 1 in the new greenlet, once with 0
// in the origin.
int err;
if (this->force_slp_switch_error()) {
err = -1;
}
else {
err = slp_switch();
}
if (err < 0) { /* error */
// Tested by
// test_greenlet.TestBrokenGreenlets.test_failed_to_slp_switch_into_running
//
// It's not clear if it's worth trying to clean up and
// continue here. Failing to switch stacks is a big deal which
// may not be recoverable (who knows what state the stack is in).
// Also, we've stolen references in preparation for calling
// ``g_switchstack_success()`` and we don't have a clean
// mechanism for backing that all out.
Py_FatalError("greenlet: Failed low-level slp_switch(). The stack is probably corrupt.");
}
// No stack-based variables are valid anymore.
// But the global is volatile so we can reload it without the
// compiler caching it from earlier.
Greenlet* greenlet_that_switched_in = switching_thread_state; // aka this
switching_thread_state = nullptr;
// except that no stack variables are valid, we would:
// assert(this == greenlet_that_switched_in);
// switchstack success is where we restore the exception state,
// etc. It returns the origin greenlet because its convenient.
OwnedGreenlet origin = greenlet_that_switched_in->g_switchstack_success();
assert(greenlet_that_switched_in->args() || PyErr_Occurred());
return switchstack_result_t(err, greenlet_that_switched_in, origin);
}
inline void
Greenlet::check_switch_allowed() const
{
// TODO: Make this take a parameter of the current greenlet,
// or current main greenlet, to make the check for
// cross-thread switching cheaper. Surely somewhere up the
// call stack we've already accessed the thread local variable.
// We expect to always have a main greenlet now; accessing the thread state
// created it. However, if we get here and cleanup has already
// begun because we're a greenlet that was running in a
// (now dead) thread, these invariants will not hold true. In
// fact, accessing `this->thread_state` may not even be possible.
// If the thread this greenlet was running in is dead,
// we'll still have a reference to a main greenlet, but the
// thread state pointer we have is bogus.
// TODO: Give the objects an API to determine if they belong
// to a dead thread.
const BorrowedMainGreenlet main_greenlet = this->find_main_greenlet_in_lineage();
if (!main_greenlet) {
throw PyErrOccurred(mod_globs->PyExc_GreenletError,
"cannot switch to a garbage collected greenlet");
}
if (!main_greenlet->thread_state()) {
throw PyErrOccurred(mod_globs->PyExc_GreenletError,
"cannot switch to a different thread (which happens to have exited)");
}
// The main greenlet we found was from the .parent lineage.
// That may or may not have any relationship to the main
// greenlet of the running thread. We can't actually access
// our this->thread_state members to try to check that,
// because it could be in the process of getting destroyed,
// but setting the main_greenlet->thread_state member to NULL
// may not be visible yet. So we need to check against the
// current thread state (once the cheaper checks are out of
// the way)
const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet();
if (
// lineage main greenlet is not this thread's greenlet
current_main_greenlet != main_greenlet
|| (
// atteched to some thread
this->main_greenlet()
// XXX: Same condition as above. Was this supposed to be
// this->main_greenlet()?
&& current_main_greenlet != main_greenlet)
// switching into a known dead thread (XXX: which, if we get here,
// is bad, because we just accessed the thread state, which is
// gone!)
|| (!current_main_greenlet->thread_state())) {
// CAUTION: This may trigger memory allocations, gc, and
// arbitrary Python code.
throw PyErrOccurred(mod_globs->PyExc_GreenletError,
"cannot switch to a different thread");
}
}
const OwnedObject
Greenlet::context() const
{
using greenlet::PythonStateContext;
OwnedObject result;
if (this->is_currently_running_in_some_thread()) {
/* Currently running greenlet: context is stored in the thread state,
not the greenlet object. */
if (GET_THREAD_STATE().state().is_current(this->self())) {
result = PythonStateContext::context(PyThreadState_GET());
}
else {
throw ValueError(
"cannot get context of a "
"greenlet that is running in a different thread");
}
}
else {
/* Greenlet is not running: just return context. */
result = this->python_state.context();
}
if (!result) {
result = OwnedObject::None();
}
return result;
}
void
Greenlet::context(BorrowedObject given)
{
using greenlet::PythonStateContext;
if (!given) {
throw AttributeError("can't delete context attribute");
}
if (given.is_None()) {
/* "Empty context" is stored as NULL, not None. */
given = nullptr;
}
//checks type, incrs refcnt
greenlet::refs::OwnedContext context(given);
PyThreadState* tstate = PyThreadState_GET();
if (this->is_currently_running_in_some_thread()) {
if (!GET_THREAD_STATE().state().is_current(this->self())) {
throw ValueError("cannot set context of a greenlet"
" that is running in a different thread");
}
/* Currently running greenlet: context is stored in the thread state,
not the greenlet object. */
OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate));
PythonStateContext::context(tstate, context.relinquish_ownership());
}
else {
/* Greenlet is not running: just set context. Note that the
greenlet may be dead.*/
this->python_state.context() = context;
}
}
/**
* CAUTION: May invoke arbitrary Python code.
*
* Figure out what the result of ``greenlet.switch(arg, kwargs)``
* should be and transfers ownership of it to the left-hand-side.
*
* If switch() was just passed an arg tuple, then we'll just return that.
* If only keyword arguments were passed, then we'll pass the keyword
* argument dict. Otherwise, we'll create a tuple of (args, kwargs) and
* return both.
*
* CAUTION: This may allocate a new tuple object, which may
* cause the Python garbage collector to run, which in turn may
* run arbitrary Python code that switches.
*/
OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept
{
// Because this may invoke arbitrary Python code, which could
// result in switching back to us, we need to get the
// arguments locally on the stack.
assert(rhs);
OwnedObject args = rhs.args();
OwnedObject kwargs = rhs.kwargs();
rhs.CLEAR();
// We shouldn't be called twice for the same switch.
assert(args || kwargs);
assert(!rhs);
if (!kwargs) {
lhs = args;
}
else if (!PyDict_Size(kwargs.borrow())) {
lhs = args;
}
else if (!PySequence_Length(args.borrow())) {
lhs = kwargs;
}
else {
// PyTuple_Pack allocates memory, may GC, may run arbitrary
// Python code.
lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow()));
}
return lhs;
}
static OwnedObject
g_handle_exit(const OwnedObject& greenlet_result)
{
if (!greenlet_result && mod_globs->PyExc_GreenletExit.PyExceptionMatches()) {
/* catch and ignore GreenletExit */
PyErrFetchParam val;
PyErr_Fetch(PyErrFetchParam(), val, PyErrFetchParam());
if (!val) {
return OwnedObject::None();
}
return OwnedObject(val);
}
if (greenlet_result) {
// package the result into a 1-tuple
// PyTuple_Pack increments the reference of its arguments,
// so we always need to decref the greenlet result;
// the owner will do that.
return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow()));
}
return OwnedObject();
}
/**
* May run arbitrary Python code.
*/
OwnedObject
Greenlet::g_switch_finish(const switchstack_result_t& err)
{
assert(err.the_new_current_greenlet == this);
ThreadState& state = *this->thread_state();
// Because calling the trace function could do arbitrary things,
// including switching away from this greenlet and then maybe
// switching back, we need to capture the arguments now so that
// they don't change.
OwnedObject result;
if (this->args()) {
result <<= this->args();
}
else {
assert(PyErr_Occurred());
}
assert(!this->args());
try {
// Our only caller handles the bad error case
assert(err.status >= 0);
assert(state.borrow_current() == this->self());
if (OwnedObject tracefunc = state.get_tracefunc()) {
assert(result || PyErr_Occurred());
g_calltrace(tracefunc,
result ? mod_globs->event_switch : mod_globs->event_throw,
err.origin_greenlet,
this->self());
}
// The above could have invoked arbitrary Python code, but
// it couldn't switch back to this object and *also*
// throw an exception, so the args won't have changed.
if (PyErr_Occurred()) {
// We get here if we fell of the end of the run() function
// raising an exception. The switch itself was
// successful, but the function raised.
// valgrind reports that memory allocated here can still
// be reached after a test run.
throw PyErrOccurred::from_current();
}
return result;
}
catch (const PyErrOccurred&) {
/* Turn switch errors into switch throws */
/* Turn trace errors into switch throws */
this->release_args();
throw;
}
}
void
Greenlet::g_calltrace(const OwnedObject& tracefunc,
const greenlet::refs::ImmortalEventName& event,
const BorrowedGreenlet& origin,
const BorrowedGreenlet& target)
{
PyErrPieces saved_exc;
try {
TracingGuard tracing_guard;
// TODO: We have saved the active exception (if any) that's
// about to be raised. In the 'throw' case, we could provide
// the exception to the tracefunction, which seems very helpful.
tracing_guard.CallTraceFunction(tracefunc, event, origin, target);
}
catch (const PyErrOccurred&) {
// In case of exceptions trace function is removed,
// and any existing exception is replaced with the tracing
// exception.
GET_THREAD_STATE().state().set_tracefunc(Py_None);
throw;
}
saved_exc.PyErrRestore();
assert(
(event == mod_globs->event_throw && PyErr_Occurred())
|| (event == mod_globs->event_switch && !PyErr_Occurred())
);
}
void
Greenlet::murder_in_place()
{
if (this->active()) {
assert(!this->is_currently_running_in_some_thread());
this->deactivate_and_free();
}
}
inline void
Greenlet::deactivate_and_free()
{
if (!this->active()) {
return;
}
// Throw away any saved stack.
this->stack_state = StackState();
assert(!this->stack_state.active());
// Throw away any Python references.
// We're holding a borrowed reference to the last
// frame we executed. Since we borrowed it, the
// normal traversal, clear, and dealloc functions
// ignore it, meaning it leaks. (The thread state
// object can't find it to clear it when that's
// deallocated either, because by definition if we
// got an object on this list, it wasn't
// running and the thread state doesn't have
// this frame.)
// So here, we *do* clear it.
this->python_state.tp_clear(true);
}
bool
Greenlet::belongs_to_thread(const ThreadState* thread_state) const
{
if (!this->thread_state() // not running anywhere, or thread
// exited
|| !thread_state) { // same, or there is no thread state.
return false;
}
return true;
}
void
Greenlet::deallocing_greenlet_in_thread(const ThreadState* current_thread_state)
{
/* Cannot raise an exception to kill the greenlet if
it is not running in the same thread! */
if (this->belongs_to_thread(current_thread_state)) {
assert(current_thread_state);
// To get here it had to have run before
/* Send the greenlet a GreenletExit exception. */
// We don't care about the return value, only whether an
// exception happened.
this->throw_GreenletExit_during_dealloc(*current_thread_state);
return;
}
// Not the same thread! Temporarily save the greenlet
// into its thread's deleteme list, *if* it exists.
// If that thread has already exited, and processed its pending
// cleanup, we'll never be able to clean everything up: we won't
// be able to raise an exception.
// That's mostly OK! Since we can't add it to a list, our refcount
// won't increase, and we'll go ahead with the DECREFs later.
ThreadState *const thread_state = this->thread_state();
if (thread_state) {
thread_state->delete_when_thread_running(this->self());
}
else {
// The thread is dead, we can't raise an exception.
// We need to make it look non-active, though, so that dealloc
// finishes killing it.
this->deactivate_and_free();
}
return;
}
int
Greenlet::tp_traverse(visitproc visit, void* arg)
{
int result;
if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) {
return result;
}
//XXX: This is ugly. But so is handling everything having to do
//with the top frame.
bool visit_top_frame = this->was_running_in_dead_thread();
// When true, the thread is dead. Our implicit weak reference to the
// frame is now all that's left; we consider ourselves to
// strongly own it now.
if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) {
return result;
}
return 0;
}
int
Greenlet::tp_clear()
{
bool own_top_frame = this->was_running_in_dead_thread();
this->exception_state.tp_clear();
this->python_state.tp_clear(own_top_frame);
return 0;
}
bool Greenlet::is_currently_running_in_some_thread() const
{
return this->stack_state.active() && !this->python_state.top_frame();
}
#if GREENLET_PY312
void GREENLET_NOINLINE(Greenlet::expose_frames)()
{
if (!this->python_state.top_frame()) {
return;
}
_PyInterpreterFrame* last_complete_iframe = nullptr;
_PyInterpreterFrame* iframe = this->python_state.top_frame()->f_frame;
while (iframe) {
// We must make a copy before looking at the iframe contents,
// since iframe might point to a portion of the greenlet's C stack
// that was spilled when switching greenlets.
_PyInterpreterFrame iframe_copy;
this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe));
if (!_PyFrame_IsIncomplete(&iframe_copy)) {
// If the iframe were OWNED_BY_CSTACK then it would always be
// incomplete. Since it's not incomplete, it's not on the C stack
// and we can access it through the original `iframe` pointer
// directly. This is important since GetFrameObject might
// lazily _create_ the frame object and we don't want the
// interpreter to lose track of it.
assert(iframe_copy.owner != FRAME_OWNED_BY_CSTACK);
// We really want to just write:
// PyFrameObject* frame = _PyFrame_GetFrameObject(iframe);
// but _PyFrame_GetFrameObject calls _PyFrame_MakeAndSetFrameObject
// which is not a visible symbol in libpython. The easiest
// way to get a public function to call it is using
// PyFrame_GetBack, which is defined as follows:
// assert(frame != NULL);
// assert(!_PyFrame_IsIncomplete(frame->f_frame));
// PyFrameObject *back = frame->f_back;
// if (back == NULL) {
// _PyInterpreterFrame *prev = frame->f_frame->previous;
// prev = _PyFrame_GetFirstComplete(prev);
// if (prev) {
// back = _PyFrame_GetFrameObject(prev);
// }
// }
// return (PyFrameObject*)Py_XNewRef(back);
if (!iframe->frame_obj) {
PyFrameObject dummy_frame;
_PyInterpreterFrame dummy_iframe;
dummy_frame.f_back = nullptr;
dummy_frame.f_frame = &dummy_iframe;
// force the iframe to be considered complete without
// needing to check its code object:
dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR;
dummy_iframe.previous = iframe;
assert(!_PyFrame_IsIncomplete(&dummy_iframe));
// Drop the returned reference immediately; the iframe
// continues to hold a strong reference
Py_XDECREF(PyFrame_GetBack(&dummy_frame));
assert(iframe->frame_obj);
}
// This is a complete frame, so make the last one of those we saw
// point at it, bypassing any incomplete frames (which may have
// been on the C stack) in between the two. We're overwriting
// last_complete_iframe->previous and need that to be reversible,
// so we store the original previous ptr in the frame object
// (which we must have created on a previous iteration through
// this loop). The frame object has a bunch of storage that is
// only used when its iframe is OWNED_BY_FRAME_OBJECT, which only
// occurs when the frame object outlives the frame's execution,
// which can't have happened yet because the frame is currently
// executing as far as the interpreter is concerned. So, we can
// reuse it for our own purposes.
assert(iframe->owner == FRAME_OWNED_BY_THREAD
|| iframe->owner == FRAME_OWNED_BY_GENERATOR);
if (last_complete_iframe) {
assert(last_complete_iframe->frame_obj);
memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
&last_complete_iframe->previous, sizeof(void *));
last_complete_iframe->previous = iframe;
}
last_complete_iframe = iframe;
}
// Frames that are OWNED_BY_FRAME_OBJECT are linked via the
// frame's f_back while all others are linked via the iframe's
// previous ptr. Since all the frames we traverse are running
// as far as the interpreter is concerned, we don't have to
// worry about the OWNED_BY_FRAME_OBJECT case.
iframe = iframe_copy.previous;
}
// Give the outermost complete iframe a null previous pointer to
// account for any potential incomplete/C-stack iframes between it
// and the actual top-of-stack
if (last_complete_iframe) {
assert(last_complete_iframe->frame_obj);
memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0],
&last_complete_iframe->previous, sizeof(void *));
last_complete_iframe->previous = nullptr;
}
}
#else
void Greenlet::expose_frames()
{
}
#endif
}; // namespace greenlet

View file

@ -1,94 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/**
* Implementation of GreenletGlobals.
*
* Format with:
* clang-format -i --style=file src/greenlet/greenlet.c
*
*
* Fix missing braces with:
* clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements"
*/
#ifndef T_GREENLET_GLOBALS
#define T_GREENLET_GLOBALS
#include "greenlet_refs.hpp"
#include "greenlet_exceptions.hpp"
#include "greenlet_thread_support.hpp"
#include "greenlet_thread_state.hpp"
namespace greenlet {
// This encapsulates what were previously module global "constants"
// established at init time.
// This is a step towards Python3 style module state that allows
// reloading.
//
// In an earlier iteration of this code, we used placement new to be
// able to allocate this object statically still, so that references
// to its members don't incur an extra pointer indirection.
// But under some scenarios, that could result in crashes at
// shutdown because apparently the destructor was getting run twice?
class GreenletGlobals
{
public:
const greenlet::refs::ImmortalEventName event_switch;
const greenlet::refs::ImmortalEventName event_throw;
const greenlet::refs::ImmortalException PyExc_GreenletError;
const greenlet::refs::ImmortalException PyExc_GreenletExit;
const greenlet::refs::ImmortalObject empty_tuple;
const greenlet::refs::ImmortalObject empty_dict;
const greenlet::refs::ImmortalString str_run;
Mutex* const thread_states_to_destroy_lock;
greenlet::cleanup_queue_t thread_states_to_destroy;
GreenletGlobals() :
event_switch("switch"),
event_throw("throw"),
PyExc_GreenletError("greenlet.error"),
PyExc_GreenletExit("greenlet.GreenletExit", PyExc_BaseException),
empty_tuple(Require(PyTuple_New(0))),
empty_dict(Require(PyDict_New())),
str_run("run"),
thread_states_to_destroy_lock(new Mutex())
{}
~GreenletGlobals()
{
// This object is (currently) effectively immortal, and not
// just because of those placement new tricks; if we try to
// deallocate the static object we allocated, and overwrote,
// we would be doing so at C++ teardown time, which is after
// the final Python GIL is released, and we can't use the API
// then.
// (The members will still be destructed, but they also don't
// do any deallocation.)
}
void queue_to_destroy(ThreadState* ts) const
{
// we're currently accessed through a static const object,
// implicitly marking our members as const, so code can't just
// call push_back (or pop_back) without casting away the
// const.
//
// Do that for callers.
greenlet::cleanup_queue_t& q = const_cast<greenlet::cleanup_queue_t&>(this->thread_states_to_destroy);
q.push_back(ts);
}
ThreadState* take_next_to_destroy() const
{
greenlet::cleanup_queue_t& q = const_cast<greenlet::cleanup_queue_t&>(this->thread_states_to_destroy);
ThreadState* result = q.back();
q.pop_back();
return result;
}
};
}; // namespace greenlet
static const greenlet::GreenletGlobals* mod_globs;
#endif // T_GREENLET_GLOBALS

View file

@ -1,155 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/**
* Implementation of greenlet::MainGreenlet.
*
* Format with:
* clang-format -i --style=file src/greenlet/greenlet.c
*
*
* Fix missing braces with:
* clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements"
*/
#include "greenlet_greenlet.hpp"
#include "greenlet_thread_state.hpp"
// Protected by the GIL. Incremented when we create a main greenlet,
// in a new thread, decremented when it is destroyed.
static Py_ssize_t G_TOTAL_MAIN_GREENLETS;
namespace greenlet {
greenlet::PythonAllocator<MainGreenlet> MainGreenlet::allocator;
void* MainGreenlet::operator new(size_t UNUSED(count))
{
return allocator.allocate(1);
}
void MainGreenlet::operator delete(void* ptr)
{
return allocator.deallocate(static_cast<MainGreenlet*>(ptr),
1);
}
MainGreenlet::MainGreenlet(PyGreenlet* p, ThreadState* state)
: Greenlet(p, StackState::make_main()),
_self(p),
_thread_state(state)
{
G_TOTAL_MAIN_GREENLETS++;
}
MainGreenlet::~MainGreenlet()
{
G_TOTAL_MAIN_GREENLETS--;
this->tp_clear();
}
ThreadState*
MainGreenlet::thread_state() const noexcept
{
return this->_thread_state;
}
void
MainGreenlet::thread_state(ThreadState* t) noexcept
{
assert(!t);
this->_thread_state = t;
}
BorrowedGreenlet
MainGreenlet::self() const noexcept
{
return BorrowedGreenlet(this->_self.borrow());
}
const BorrowedMainGreenlet
MainGreenlet::main_greenlet() const
{
return this->_self;
}
BorrowedMainGreenlet
MainGreenlet::find_main_greenlet_in_lineage() const
{
return BorrowedMainGreenlet(this->_self);
}
bool
MainGreenlet::was_running_in_dead_thread() const noexcept
{
return !this->_thread_state;
}
OwnedObject
MainGreenlet::g_switch()
{
try {
this->check_switch_allowed();
}
catch (const PyErrOccurred&) {
this->release_args();
throw;
}
switchstack_result_t err = this->g_switchstack();
if (err.status < 0) {
// XXX: This code path is untested, but it is shared
// with the UserGreenlet path that is tested.
return this->on_switchstack_or_initialstub_failure(
this,
err,
true, // target was me
false // was initial stub
);
}
return err.the_new_current_greenlet->g_switch_finish(err);
}
int
MainGreenlet::tp_traverse(visitproc visit, void* arg)
{
if (this->_thread_state) {
// we've already traversed main, (self), don't do it again.
int result = this->_thread_state->tp_traverse(visit, arg, false);
if (result) {
return result;
}
}
return Greenlet::tp_traverse(visit, arg);
}
const OwnedObject&
MainGreenlet::run() const
{
throw AttributeError("Main greenlets do not have a run attribute.");
}
void
MainGreenlet::run(const BorrowedObject UNUSED(nrun))
{
throw AttributeError("Main greenlets do not have a run attribute.");
}
void
MainGreenlet::parent(const BorrowedObject raw_new_parent)
{
if (!raw_new_parent) {
throw AttributeError("can't delete attribute");
}
throw AttributeError("cannot set the parent of a main greenlet");
}
const OwnedGreenlet
MainGreenlet::parent() const
{
return OwnedGreenlet(); // null becomes None
}
}; // namespace greenlet

View file

@ -1,375 +0,0 @@
#ifndef GREENLET_PYTHON_STATE_CPP
#define GREENLET_PYTHON_STATE_CPP
#include <Python.h>
#include "greenlet_greenlet.hpp"
namespace greenlet {
PythonState::PythonState()
: _top_frame()
#if GREENLET_USE_CFRAME
,cframe(nullptr)
,use_tracing(0)
#endif
#if GREENLET_PY312
,py_recursion_depth(0)
,c_recursion_depth(0)
#else
,recursion_depth(0)
#endif
,trash_delete_nesting(0)
#if GREENLET_PY311
,current_frame(nullptr)
,datastack_chunk(nullptr)
,datastack_top(nullptr)
,datastack_limit(nullptr)
#endif
{
#if GREENLET_USE_CFRAME
/*
The PyThreadState->cframe pointer usually points to memory on
the stack, alloceted in a call into PyEval_EvalFrameDefault.
Initially, before any evaluation begins, it points to the
initial PyThreadState object's ``root_cframe`` object, which is
statically allocated for the lifetime of the thread.
A greenlet can last for longer than a call to
PyEval_EvalFrameDefault, so we can't set its ``cframe`` pointer
to be the current ``PyThreadState->cframe``; nor could we use
one from the greenlet parent for the same reason. Yet a further
no: we can't allocate one scoped to the greenlet and then
destroy it when the greenlet is deallocated, because inside the
interpreter the _PyCFrame objects form a linked list, and that too
can result in accessing memory beyond its dynamic lifetime (if
the greenlet doesn't actually finish before it dies, its entry
could still be in the list).
Using the ``root_cframe`` is problematic, though, because its
members are never modified by the interpreter and are set to 0,
meaning that its ``use_tracing`` flag is never updated. We don't
want to modify that value in the ``root_cframe`` ourself: it
*shouldn't* matter much because we should probably never get
back to the point where that's the only cframe on the stack;
even if it did matter, the major consequence of an incorrect
value for ``use_tracing`` is that if its true the interpreter
does some extra work --- however, it's just good code hygiene.
Our solution: before a greenlet runs, after its initial
creation, it uses the ``root_cframe`` just to have something to
put there. However, once the greenlet is actually switched to
for the first time, ``g_initialstub`` (which doesn't actually
"return" while the greenlet is running) stores a new _PyCFrame on
its local stack, and copies the appropriate values from the
currently running _PyCFrame; this is then made the _PyCFrame for the
newly-minted greenlet. ``g_initialstub`` then proceeds to call
``glet.run()``, which results in ``PyEval_...`` adding the
_PyCFrame to the list. Switches continue as normal. Finally, when
the greenlet finishes, the call to ``glet.run()`` returns and
the _PyCFrame is taken out of the linked list and the stack value
is now unused and free to expire.
XXX: I think we can do better. If we're deallocing in the same
thread, can't we traverse the list and unlink our frame?
Can we just keep a reference to the thread state in case we
dealloc in another thread? (Is that even possible if we're still
running and haven't returned from g_initialstub?)
*/
this->cframe = &PyThreadState_GET()->root_cframe;
#endif
}
inline void PythonState::may_switch_away() noexcept
{
#if GREENLET_PY311
// PyThreadState_GetFrame is probably going to have to allocate a
// new frame object. That may trigger garbage collection. Because
// we call this during the early phases of a switch (it doesn't
// matter to which greenlet, as this has a global effect), if a GC
// triggers a switch away, two things can happen, both bad:
// - We might not get switched back to, halting forward progress.
// this is pathological, but possible.
// - We might get switched back to with a different set of
// arguments or a throw instead of a switch. That would corrupt
// our state (specifically, PyErr_Occurred() and this->args()
// would no longer agree).
//
// Thus, when we call this API, we need to have GC disabled.
// This method serves as a bottleneck we call when maybe beginning
// a switch. In this way, it is always safe -- no risk of GC -- to
// use ``_GetFrame()`` whenever we need to, just as it was in
// <=3.10 (because subsequent calls will be cached and not
// allocate memory).
GCDisabledGuard no_gc;
Py_XDECREF(PyThreadState_GetFrame(PyThreadState_GET()));
#endif
}
void PythonState::operator<<(const PyThreadState *const tstate) noexcept
{
this->_context.steal(tstate->context);
#if GREENLET_USE_CFRAME
/*
IMPORTANT: ``cframe`` is a pointer into the STACK. Thus, because
the call to ``slp_switch()`` changes the contents of the stack,
you cannot read from ``ts_current->cframe`` after that call and
necessarily get the same values you get from reading it here.
Anything you need to restore from now to then must be saved in a
global/threadlocal variable (because we can't use stack
variables here either). For things that need to persist across
the switch, use `will_switch_from`.
*/
this->cframe = tstate->cframe;
#if !GREENLET_PY312
this->use_tracing = tstate->cframe->use_tracing;
#endif
#endif // GREENLET_USE_CFRAME
#if GREENLET_PY311
#if GREENLET_PY312
this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
this->c_recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining;
#else // not 312
this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
#endif // GREENLET_PY312
this->current_frame = tstate->cframe->current_frame;
this->datastack_chunk = tstate->datastack_chunk;
this->datastack_top = tstate->datastack_top;
this->datastack_limit = tstate->datastack_limit;
PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate);
Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new
// reference.
this->_top_frame.steal(frame);
#if GREENLET_PY312
this->trash_delete_nesting = tstate->trash.delete_nesting;
#else // not 312
this->trash_delete_nesting = tstate->trash_delete_nesting;
#endif // GREENLET_PY312
#else // Not 311
this->recursion_depth = tstate->recursion_depth;
this->_top_frame.steal(tstate->frame);
this->trash_delete_nesting = tstate->trash_delete_nesting;
#endif // GREENLET_PY311
}
#if GREENLET_PY312
void GREENLET_NOINLINE(PythonState::unexpose_frames)()
{
if (!this->top_frame()) {
return;
}
// See GreenletState::expose_frames() and the comment on frames_were_exposed
// for more information about this logic.
_PyInterpreterFrame *iframe = this->_top_frame->f_frame;
while (iframe != nullptr) {
_PyInterpreterFrame *prev_exposed = iframe->previous;
assert(iframe->frame_obj);
memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0],
sizeof(void *));
iframe = prev_exposed;
}
}
#else
void PythonState::unexpose_frames()
{}
#endif
void PythonState::operator>>(PyThreadState *const tstate) noexcept
{
tstate->context = this->_context.relinquish_ownership();
/* Incrementing this value invalidates the contextvars cache,
which would otherwise remain valid across switches */
tstate->context_ver++;
#if GREENLET_USE_CFRAME
tstate->cframe = this->cframe;
/*
If we were tracing, we need to keep tracing.
There should never be the possibility of hitting the
root_cframe here. See note above about why we can't
just copy this from ``origin->cframe->use_tracing``.
*/
#if !GREENLET_PY312
tstate->cframe->use_tracing = this->use_tracing;
#endif
#endif // GREENLET_USE_CFRAME
#if GREENLET_PY311
#if GREENLET_PY312
tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth;
tstate->c_recursion_remaining = C_RECURSION_LIMIT - this->c_recursion_depth;
this->unexpose_frames();
#else // \/ 3.11
tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth;
#endif // GREENLET_PY312
tstate->cframe->current_frame = this->current_frame;
tstate->datastack_chunk = this->datastack_chunk;
tstate->datastack_top = this->datastack_top;
tstate->datastack_limit = this->datastack_limit;
this->_top_frame.relinquish_ownership();
#if GREENLET_PY312
tstate->trash.delete_nesting = this->trash_delete_nesting;
#else // not 3.12
tstate->trash_delete_nesting = this->trash_delete_nesting;
#endif // GREENLET_PY312
#else // not 3.11
tstate->frame = this->_top_frame.relinquish_ownership();
tstate->recursion_depth = this->recursion_depth;
tstate->trash_delete_nesting = this->trash_delete_nesting;
#endif // GREENLET_PY311
}
inline void PythonState::will_switch_from(PyThreadState *const origin_tstate) noexcept
{
#if GREENLET_USE_CFRAME && !GREENLET_PY312
// The weird thing is, we don't actually save this for an
// effect on the current greenlet, it's saved for an
// effect on the target greenlet. That is, we want
// continuity of this setting across the greenlet switch.
this->use_tracing = origin_tstate->cframe->use_tracing;
#endif
}
void PythonState::set_initial_state(const PyThreadState* const tstate) noexcept
{
this->_top_frame = nullptr;
#if GREENLET_PY312
this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
// XXX: TODO: Comment from a reviewer:
// Should this be ``C_RECURSION_LIMIT - tstate->c_recursion_remaining``?
// But to me it looks more like that might not be the right
// initialization either?
this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining;
#elif GREENLET_PY311
this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;
#else
this->recursion_depth = tstate->recursion_depth;
#endif
}
// TODO: Better state management about when we own the top frame.
int PythonState::tp_traverse(visitproc visit, void* arg, bool own_top_frame) noexcept
{
Py_VISIT(this->_context.borrow());
if (own_top_frame) {
Py_VISIT(this->_top_frame.borrow());
}
return 0;
}
void PythonState::tp_clear(bool own_top_frame) noexcept
{
PythonStateContext::tp_clear();
// If we get here owning a frame,
// we got dealloc'd without being finished. We may or may not be
// in the same thread.
if (own_top_frame) {
this->_top_frame.CLEAR();
}
}
#if GREENLET_USE_CFRAME
void PythonState::set_new_cframe(_PyCFrame& frame) noexcept
{
frame = *PyThreadState_GET()->cframe;
/* Make the target greenlet refer to the stack value. */
this->cframe = &frame;
/*
And restore the link to the previous frame so this one gets
unliked appropriately.
*/
this->cframe->previous = &PyThreadState_GET()->root_cframe;
}
#endif
const PythonState::OwnedFrame& PythonState::top_frame() const noexcept
{
return this->_top_frame;
}
void PythonState::did_finish(PyThreadState* tstate) noexcept
{
#if GREENLET_PY311
// See https://github.com/gevent/gevent/issues/1924 and
// https://github.com/python-greenlet/greenlet/issues/328. In
// short, Python 3.11 allocates memory for frames as a sort of
// linked list that's kept as part of PyThreadState in the
// ``datastack_chunk`` member and friends. These are saved and
// restored as part of switching greenlets.
//
// When we initially switch to a greenlet, we set those to NULL.
// That causes the frame management code to treat this like a
// brand new thread and start a fresh list of chunks, beginning
// with a new "root" chunk. As we make calls in this greenlet,
// those chunks get added, and as calls return, they get popped.
// But the frame code (pystate.c) is careful to make sure that the
// root chunk never gets popped.
//
// Thus, when a greenlet exits for the last time, there will be at
// least a single root chunk that we must be responsible for
// deallocating.
//
// The complex part is that these chunks are allocated and freed
// using ``_PyObject_VirtualAlloc``/``Free``. Those aren't public
// functions, and they aren't exported for linking. It so happens
// that we know they are just thin wrappers around the Arena
// allocator, so we can use that directly to deallocate in a
// compatible way.
//
// CAUTION: Check this implementation detail on every major version.
//
// It might be nice to be able to do this in our destructor, but
// can we be sure that no one else is using that memory? Plus, as
// described below, our pointers may not even be valid anymore. As
// a special case, there is one time that we know we can do this,
// and that's from the destructor of the associated UserGreenlet
// (NOT main greenlet)
PyObjectArenaAllocator alloc;
_PyStackChunk* chunk = nullptr;
if (tstate) {
// We really did finish, we can never be switched to again.
chunk = tstate->datastack_chunk;
// Unfortunately, we can't do much sanity checking. Our
// this->datastack_chunk pointer is out of date (evaluation may
// have popped down through it already) so we can't verify that
// we deallocate it. I don't think we can even check datastack_top
// for the same reason.
PyObject_GetArenaAllocator(&alloc);
tstate->datastack_chunk = nullptr;
tstate->datastack_limit = nullptr;
tstate->datastack_top = nullptr;
}
else if (this->datastack_chunk) {
// The UserGreenlet (NOT the main greenlet!) is being deallocated. If we're
// still holding a stack chunk, it's garbage because we know
// we can never switch back to let cPython clean it up.
// Because the last time we got switched away from, and we
// haven't run since then, we know our chain is valid and can
// be dealloced.
chunk = this->datastack_chunk;
PyObject_GetArenaAllocator(&alloc);
}
if (alloc.free && chunk) {
// In case the arena mechanism has been torn down already.
while (chunk) {
_PyStackChunk *prev = chunk->previous;
chunk->previous = nullptr;
alloc.free(alloc.ctx, chunk, chunk->size);
chunk = prev;
}
}
this->datastack_chunk = nullptr;
this->datastack_limit = nullptr;
this->datastack_top = nullptr;
#endif
}
}; // namespace greenlet
#endif // GREENLET_PYTHON_STATE_CPP

View file

@ -1,265 +0,0 @@
#ifndef GREENLET_STACK_STATE_CPP
#define GREENLET_STACK_STATE_CPP
#include "greenlet_greenlet.hpp"
namespace greenlet {
#ifdef GREENLET_USE_STDIO
#include <iostream>
using std::cerr;
using std::endl;
std::ostream& operator<<(std::ostream& os, const StackState& s)
{
os << "StackState(stack_start=" << (void*)s._stack_start
<< ", stack_stop=" << (void*)s.stack_stop
<< ", stack_copy=" << (void*)s.stack_copy
<< ", stack_saved=" << s._stack_saved
<< ", stack_prev=" << s.stack_prev
<< ", addr=" << &s
<< ")";
return os;
}
#endif
StackState::StackState(void* mark, StackState& current)
: _stack_start(nullptr),
stack_stop((char*)mark),
stack_copy(nullptr),
_stack_saved(0),
/* Skip a dying greenlet */
stack_prev(current._stack_start
? &current
: current.stack_prev)
{
}
StackState::StackState()
: _stack_start(nullptr),
stack_stop(nullptr),
stack_copy(nullptr),
_stack_saved(0),
stack_prev(nullptr)
{
}
StackState::StackState(const StackState& other)
// can't use a delegating constructor because of
// MSVC for Python 2.7
: _stack_start(nullptr),
stack_stop(nullptr),
stack_copy(nullptr),
_stack_saved(0),
stack_prev(nullptr)
{
this->operator=(other);
}
StackState& StackState::operator=(const StackState& other)
{
if (&other == this) {
return *this;
}
if (other._stack_saved) {
throw std::runtime_error("Refusing to steal memory.");
}
//If we have memory allocated, dispose of it
this->free_stack_copy();
this->_stack_start = other._stack_start;
this->stack_stop = other.stack_stop;
this->stack_copy = other.stack_copy;
this->_stack_saved = other._stack_saved;
this->stack_prev = other.stack_prev;
return *this;
}
inline void StackState::free_stack_copy() noexcept
{
PyMem_Free(this->stack_copy);
this->stack_copy = nullptr;
this->_stack_saved = 0;
}
inline void StackState::copy_heap_to_stack(const StackState& current) noexcept
{
/* Restore the heap copy back into the C stack */
if (this->_stack_saved != 0) {
memcpy(this->_stack_start, this->stack_copy, this->_stack_saved);
this->free_stack_copy();
}
StackState* owner = const_cast<StackState*>(&current);
if (!owner->_stack_start) {
owner = owner->stack_prev; /* greenlet is dying, skip it */
}
while (owner && owner->stack_stop <= this->stack_stop) {
// cerr << "\tOwner: " << owner << endl;
owner = owner->stack_prev; /* find greenlet with more stack */
}
this->stack_prev = owner;
// cerr << "\tFinished with: " << *this << endl;
}
inline int StackState::copy_stack_to_heap_up_to(const char* const stop) noexcept
{
/* Save more of g's stack into the heap -- at least up to 'stop'
g->stack_stop |________|
| |
| __ stop . . . . .
| | ==> . .
|________| _______
| | | |
| | | |
g->stack_start | | |_______| g->stack_copy
*/
intptr_t sz1 = this->_stack_saved;
intptr_t sz2 = stop - this->_stack_start;
assert(this->_stack_start);
if (sz2 > sz1) {
char* c = (char*)PyMem_Realloc(this->stack_copy, sz2);
if (!c) {
PyErr_NoMemory();
return -1;
}
memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1);
this->stack_copy = c;
this->_stack_saved = sz2;
}
return 0;
}
inline int StackState::copy_stack_to_heap(char* const stackref,
const StackState& current) noexcept
{
/* must free all the C stack up to target_stop */
const char* const target_stop = this->stack_stop;
StackState* owner = const_cast<StackState*>(&current);
assert(owner->_stack_saved == 0); // everything is present on the stack
if (!owner->_stack_start) {
owner = owner->stack_prev; /* not saved if dying */
}
else {
owner->_stack_start = stackref;
}
while (owner->stack_stop < target_stop) {
/* ts_current is entierely within the area to free */
if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) {
return -1; /* XXX */
}
owner = owner->stack_prev;
}
if (owner != this) {
if (owner->copy_stack_to_heap_up_to(target_stop)) {
return -1; /* XXX */
}
}
return 0;
}
inline bool StackState::started() const noexcept
{
return this->stack_stop != nullptr;
}
inline bool StackState::main() const noexcept
{
return this->stack_stop == (char*)-1;
}
inline bool StackState::active() const noexcept
{
return this->_stack_start != nullptr;
}
inline void StackState::set_active() noexcept
{
assert(this->_stack_start == nullptr);
this->_stack_start = (char*)1;
}
inline void StackState::set_inactive() noexcept
{
this->_stack_start = nullptr;
// XXX: What if we still have memory out there?
// That case is actually triggered by
// test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks)
// and
// test_issue251_issue252_need_to_collect_in_background
// (greenlet.tests.test_leaks.TestLeaks)
//
// Those objects never get deallocated, so the destructor never
// runs.
// It *seems* safe to clean up the memory here?
if (this->_stack_saved) {
this->free_stack_copy();
}
}
inline intptr_t StackState::stack_saved() const noexcept
{
return this->_stack_saved;
}
inline char* StackState::stack_start() const noexcept
{
return this->_stack_start;
}
inline StackState StackState::make_main() noexcept
{
StackState s;
s._stack_start = (char*)1;
s.stack_stop = (char*)-1;
return s;
}
StackState::~StackState()
{
if (this->_stack_saved != 0) {
this->free_stack_copy();
}
}
void StackState::copy_from_stack(void* vdest, const void* vsrc, size_t n) const
{
char* dest = static_cast<char*>(vdest);
const char* src = static_cast<const char*>(vsrc);
if (src + n <= this->_stack_start
|| src >= this->_stack_start + this->_stack_saved
|| this->_stack_saved == 0) {
// Nothing we're copying was spilled from the stack
memcpy(dest, src, n);
return;
}
if (src < this->_stack_start) {
// Copy the part before the saved stack.
// We know src + n > _stack_start due to the test above.
const size_t nbefore = this->_stack_start - src;
memcpy(dest, src, nbefore);
dest += nbefore;
src += nbefore;
n -= nbefore;
}
// We know src >= _stack_start after the before-copy, and
// src < _stack_start + _stack_saved due to the first if condition
size_t nspilled = std::min<size_t>(n, this->_stack_start + this->_stack_saved - src);
memcpy(dest, this->stack_copy + (src - this->_stack_start), nspilled);
dest += nspilled;
src += nspilled;
n -= nspilled;
if (n > 0) {
// Copy the part after the saved stack
memcpy(dest, src, n);
}
}
}; // namespace greenlet
#endif // GREENLET_STACK_STATE_CPP

View file

@ -1,195 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/**
* Implementation of the ThreadState destructors.
*
* Format with:
* clang-format -i --style=file src/greenlet/greenlet.c
*
*
* Fix missing braces with:
* clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements"
*/
#ifndef T_THREADSTATE_DESTROY
#define T_THREADSTATE_DESTROY
#include "greenlet_greenlet.hpp"
#include "greenlet_thread_state.hpp"
#include "greenlet_thread_support.hpp"
#include "greenlet_cpython_add_pending.hpp"
#include "TGreenletGlobals.cpp"
namespace greenlet {
struct ThreadState_DestroyWithGIL
{
ThreadState_DestroyWithGIL(ThreadState* state)
{
if (state && state->has_main_greenlet()) {
DestroyWithGIL(state);
}
}
static int
DestroyWithGIL(ThreadState* state)
{
// Holding the GIL.
// Passed a non-shared pointer to the actual thread state.
// state -> main greenlet
assert(state->has_main_greenlet());
PyGreenlet* main(state->borrow_main_greenlet());
// When we need to do cross-thread operations, we check this.
// A NULL value means the thread died some time ago.
// We do this here, rather than in a Python dealloc function
// for the greenlet, in case there's still a reference out
// there.
static_cast<MainGreenlet*>(main->pimpl)->thread_state(nullptr);
delete state; // Deleting this runs the destructor, DECREFs the main greenlet.
return 0;
}
};
struct ThreadState_DestroyNoGIL
{
// ensure this is actually defined.
static_assert(GREENLET_BROKEN_PY_ADD_PENDING == 1 || GREENLET_BROKEN_PY_ADD_PENDING == 0,
"GREENLET_BROKEN_PY_ADD_PENDING not defined correctly.");
#if GREENLET_BROKEN_PY_ADD_PENDING
static int _push_pending_call(struct _pending_calls *pending,
int (*func)(void *), void *arg)
{
int i = pending->last;
int j = (i + 1) % NPENDINGCALLS;
if (j == pending->first) {
return -1; /* Queue full */
}
pending->calls[i].func = func;
pending->calls[i].arg = arg;
pending->last = j;
return 0;
}
static int AddPendingCall(int (*func)(void *), void *arg)
{
_PyRuntimeState *runtime = &_PyRuntime;
if (!runtime) {
// obviously impossible
return 0;
}
struct _pending_calls *pending = &runtime->ceval.pending;
if (!pending->lock) {
return 0;
}
int result = 0;
PyThread_acquire_lock(pending->lock, WAIT_LOCK);
if (!pending->finishing) {
result = _push_pending_call(pending, func, arg);
}
PyThread_release_lock(pending->lock);
SIGNAL_PENDING_CALLS(&runtime->ceval);
return result;
}
#else
// Python < 3.8 or >= 3.9
static int AddPendingCall(int (*func)(void*), void* arg)
{
return Py_AddPendingCall(func, arg);
}
#endif
ThreadState_DestroyNoGIL(ThreadState* state)
{
// We are *NOT* holding the GIL. Our thread is in the middle
// of its death throes and the Python thread state is already
// gone so we can't use most Python APIs. One that is safe is
// ``Py_AddPendingCall``, unless the interpreter itself has
// been torn down. There is a limited number of calls that can
// be queued: 32 (NPENDINGCALLS) in CPython 3.10, so we
// coalesce these calls using our own queue.
if (state && state->has_main_greenlet()) {
// mark the thread as dead ASAP.
// this is racy! If we try to throw or switch to a
// greenlet from this thread from some other thread before
// we clear the state pointer, it won't realize the state
// is dead which can crash the process.
PyGreenlet* p = state->borrow_main_greenlet();
assert(p->pimpl->thread_state() == state || p->pimpl->thread_state() == nullptr);
static_cast<MainGreenlet*>(p->pimpl)->thread_state(nullptr);
}
// NOTE: Because we're not holding the GIL here, some other
// Python thread could run and call ``os.fork()``, which would
// be bad if that happenend while we are holding the cleanup
// lock (it wouldn't function in the child process).
// Make a best effort to try to keep the duration we hold the
// lock short.
// TODO: On platforms that support it, use ``pthread_atfork`` to
// drop this lock.
LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock);
if (state && state->has_main_greenlet()) {
// Because we don't have the GIL, this is a race condition.
if (!PyInterpreterState_Head()) {
// We have to leak the thread state, if the
// interpreter has shut down when we're getting
// deallocated, we can't run the cleanup code that
// deleting it would imply.
return;
}
mod_globs->queue_to_destroy(state);
if (mod_globs->thread_states_to_destroy.size() == 1) {
// We added the first item to the queue. We need to schedule
// the cleanup.
int result = ThreadState_DestroyNoGIL::AddPendingCall(
ThreadState_DestroyNoGIL::DestroyQueueWithGIL,
NULL);
if (result < 0) {
// Hmm, what can we do here?
fprintf(stderr,
"greenlet: WARNING: failed in call to Py_AddPendingCall; "
"expect a memory leak.\n");
}
}
}
}
static int
DestroyQueueWithGIL(void* UNUSED(arg))
{
// We're holding the GIL here, so no Python code should be able to
// run to call ``os.fork()``.
while (1) {
ThreadState* to_destroy;
{
LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock);
if (mod_globs->thread_states_to_destroy.empty()) {
break;
}
to_destroy = mod_globs->take_next_to_destroy();
}
// Drop the lock while we do the actual deletion.
ThreadState_DestroyWithGIL::DestroyWithGIL(to_destroy);
}
return 0;
}
};
}; // namespace greenlet
// The intent when GET_THREAD_STATE() is needed multiple times in a
// function is to take a reference to its return value in a local
// variable, to avoid the thread-local indirection. On some platforms
// (macOS), accessing a thread-local involves a function call (plus an
// initial function call in each function that uses a thread local);
// in contrast, static volatile variables are at some pre-computed
// offset.
typedef greenlet::ThreadStateCreator<greenlet::ThreadState_DestroyNoGIL> ThreadStateCreator;
static thread_local ThreadStateCreator g_thread_state_global;
#define GET_THREAD_STATE() g_thread_state_global
#endif //T_THREADSTATE_DESTROY

View file

@ -1,667 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/**
* Implementation of greenlet::UserGreenlet.
*
* Format with:
* clang-format -i --style=file src/greenlet/greenlet.c
*
*
* Fix missing braces with:
* clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements"
*/
#include "greenlet_internal.hpp"
#include "greenlet_greenlet.hpp"
#include "greenlet_thread_state.hpp"
#include "TThreadStateDestroy.cpp"
namespace greenlet {
using greenlet::refs::BorrowedMainGreenlet;
greenlet::PythonAllocator<UserGreenlet> UserGreenlet::allocator;
void* UserGreenlet::operator new(size_t UNUSED(count))
{
return allocator.allocate(1);
}
void UserGreenlet::operator delete(void* ptr)
{
return allocator.deallocate(static_cast<UserGreenlet*>(ptr),
1);
}
UserGreenlet::UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent)
: Greenlet(p), _parent(the_parent)
{
this->_self = p;
}
UserGreenlet::~UserGreenlet()
{
// Python 3.11: If we don't clear out the raw frame datastack
// when deleting an unfinished greenlet,
// TestLeaks.test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main fails.
this->python_state.did_finish(nullptr);
this->tp_clear();
}
BorrowedGreenlet
UserGreenlet::self() const noexcept
{
return this->_self;
}
const BorrowedMainGreenlet
UserGreenlet::main_greenlet() const
{
return this->_main_greenlet;
}
BorrowedMainGreenlet
UserGreenlet::find_main_greenlet_in_lineage() const
{
if (this->started()) {
assert(this->_main_greenlet);
return BorrowedMainGreenlet(this->_main_greenlet);
}
if (!this->_parent) {
/* garbage collected greenlet in chain */
// XXX: WHAT?
return BorrowedMainGreenlet(nullptr);
}
return this->_parent->find_main_greenlet_in_lineage();
}
/**
* CAUTION: This will allocate memory and may trigger garbage
* collection and arbitrary Python code.
*/
OwnedObject
UserGreenlet::throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state)
{
/* The dying greenlet cannot be a parent of ts_current
because the 'parent' field chain would hold a
reference */
UserGreenlet::ParentIsCurrentGuard with_current_parent(this, current_thread_state);
// We don't care about the return value, only whether an
// exception happened. Whether or not an exception happens,
// we need to restore the parent in case the greenlet gets
// resurrected.
return Greenlet::throw_GreenletExit_during_dealloc(current_thread_state);
}
ThreadState*
UserGreenlet::thread_state() const noexcept
{
// TODO: maybe make this throw, if the thread state isn't there?
// if (!this->main_greenlet) {
// throw std::runtime_error("No thread state"); // TODO: Better exception
// }
if (!this->_main_greenlet) {
return nullptr;
}
return this->_main_greenlet->thread_state();
}
bool
UserGreenlet::was_running_in_dead_thread() const noexcept
{
return this->_main_greenlet && !this->thread_state();
}
OwnedObject
UserGreenlet::g_switch()
{
assert(this->args() || PyErr_Occurred());
try {
this->check_switch_allowed();
}
catch (const PyErrOccurred&) {
this->release_args();
throw;
}
// Switching greenlets used to attempt to clean out ones that need
// deleted *if* we detected a thread switch. Should it still do
// that?
// An issue is that if we delete a greenlet from another thread,
// it gets queued to this thread, and ``kill_greenlet()`` switches
// back into the greenlet
/* find the real target by ignoring dead greenlets,
and if necessary starting a greenlet. */
switchstack_result_t err;
Greenlet* target = this;
// TODO: probably cleaner to handle the case where we do
// switch to ourself separately from the other cases.
// This can probably even further be simplified if we keep
// track of the switching_state we're going for and just call
// into g_switch() if it's not ourself. The main problem with that
// is that we would be using more stack space.
bool target_was_me = true;
bool was_initial_stub = false;
while (target) {
if (target->active()) {
if (!target_was_me) {
target->args() <<= this->args();
assert(!this->args());
}
err = target->g_switchstack();
break;
}
if (!target->started()) {
// We never encounter a main greenlet that's not started.
assert(!target->main());
UserGreenlet* real_target = static_cast<UserGreenlet*>(target);
assert(real_target);
void* dummymarker;
was_initial_stub = true;
if (!target_was_me) {
target->args() <<= this->args();
assert(!this->args());
}
try {
// This can only throw back to us while we're
// still in this greenlet. Once the new greenlet
// is bootstrapped, it has its own exception state.
err = real_target->g_initialstub(&dummymarker);
}
catch (const PyErrOccurred&) {
this->release_args();
throw;
}
catch (const GreenletStartedWhileInPython&) {
// The greenlet was started sometime before this
// greenlet actually switched to it, i.e.,
// "concurrent" calls to switch() or throw().
// We need to retry the switch.
// Note that the current greenlet has been reset
// to this one (or we wouldn't be running!)
continue;
}
break;
}
target = target->parent();
target_was_me = false;
}
// The ``this`` pointer and all other stack or register based
// variables are invalid now, at least where things succeed
// above.
// But this one, probably not so much? It's not clear if it's
// safe to throw an exception at this point.
if (err.status < 0) {
// If we get here, either g_initialstub()
// failed, or g_switchstack() failed. Either one of those
// cases SHOULD leave us in the original greenlet with a valid
// stack.
return this->on_switchstack_or_initialstub_failure(target, err, target_was_me, was_initial_stub);
}
// err.the_new_current_greenlet would be the same as ``target``,
// if target wasn't probably corrupt.
return err.the_new_current_greenlet->g_switch_finish(err);
}
Greenlet::switchstack_result_t
UserGreenlet::g_initialstub(void* mark)
{
OwnedObject run;
// We need to grab a reference to the current switch arguments
// in case we're entered concurrently during the call to
// GetAttr() and have to try again.
// We'll restore them when we return in that case.
// Scope them tightly to avoid ref leaks.
{
SwitchingArgs args(this->args());
/* save exception in case getattr clears it */
PyErrPieces saved;
/*
self.run is the object to call in the new greenlet.
This could run arbitrary python code and switch greenlets!
*/
run = this->_self.PyRequireAttr(mod_globs->str_run);
/* restore saved exception */
saved.PyErrRestore();
/* recheck that it's safe to switch in case greenlet reparented anywhere above */
this->check_switch_allowed();
/* by the time we got here another start could happen elsewhere,
* that means it should now be a regular switch.
* This can happen if the Python code is a subclass that implements
* __getattribute__ or __getattr__, or makes ``run`` a descriptor;
* all of those can run arbitrary code that switches back into
* this greenlet.
*/
if (this->stack_state.started()) {
// the successful switch cleared these out, we need to
// restore our version. They will be copied on up to the
// next target.
assert(!this->args());
this->args() <<= args;
throw GreenletStartedWhileInPython();
}
}
// Sweet, if we got here, we have the go-ahead and will switch
// greenlets.
// Nothing we do from here on out should allow for a thread or
// greenlet switch: No arbitrary calls to Python, including
// decref'ing
#if GREENLET_USE_CFRAME
/* OK, we need it, we're about to switch greenlets, save the state. */
/*
See green_new(). This is a stack-allocated variable used
while *self* is in PyObject_Call().
We want to defer copying the state info until we're sure
we need it and are in a stable place to do so.
*/
_PyCFrame trace_info;
this->python_state.set_new_cframe(trace_info);
#endif
/* start the greenlet */
ThreadState& thread_state = GET_THREAD_STATE().state();
this->stack_state = StackState(mark,
thread_state.borrow_current()->stack_state);
this->python_state.set_initial_state(PyThreadState_GET());
this->exception_state.clear();
this->_main_greenlet = thread_state.get_main_greenlet();
/* perform the initial switch */
switchstack_result_t err = this->g_switchstack();
/* returns twice!
The 1st time with ``err == 1``: we are in the new greenlet.
This one owns a greenlet that used to be current.
The 2nd time with ``err <= 0``: back in the caller's
greenlet; this happens if the child finishes or switches
explicitly to us. Either way, the ``err`` variable is
created twice at the same memory location, but possibly
having different ``origin`` values. Note that it's not
constructed for the second time until the switch actually happens.
*/
if (err.status == 1) {
// In the new greenlet.
// This never returns! Calling inner_bootstrap steals
// the contents of our run object within this stack frame, so
// it is not valid to do anything with it.
try {
this->inner_bootstrap(err.origin_greenlet.relinquish_ownership(),
run.relinquish_ownership());
}
// Getting a C++ exception here isn't good. It's probably a
// bug in the underlying greenlet, meaning it's probably a
// C++ extension. We're going to abort anyway, but try to
// display some nice information *if* possible. Some obscure
// platforms don't properly support this (old 32-bit Arm, see see
// https://github.com/python-greenlet/greenlet/issues/385); that's not
// great, but should usually be OK because, as mentioned above, we're
// terminating anyway.
//
// The catching is tested by
// ``test_cpp.CPPTests.test_unhandled_exception_in_greenlet_aborts``.
//
// PyErrOccurred can theoretically be thrown by
// inner_bootstrap() -> g_switch_finish(), but that should
// never make it back to here. It is a std::exception and
// would be caught if it is.
catch (const std::exception& e) {
std::string base = "greenlet: Unhandled C++ exception: ";
base += e.what();
Py_FatalError(base.c_str());
}
catch (...) {
// Some compilers/runtimes use exceptions internally.
// It appears that GCC on Linux with libstdc++ throws an
// exception internally at process shutdown time to unwind
// stacks and clean up resources. Depending on exactly
// where we are when the process exits, that could result
// in an unknown exception getting here. If we
// Py_FatalError() or abort() here, we interfere with
// orderly process shutdown. Throwing the exception on up
// is the right thing to do.
//
// gevent's ``examples/dns_mass_resolve.py`` demonstrates this.
#ifndef NDEBUG
fprintf(stderr,
"greenlet: inner_bootstrap threw unknown exception; "
"is the process terminating?\n");
#endif
throw;
}
Py_FatalError("greenlet: inner_bootstrap returned with no exception.\n");
}
// In contrast, notice that we're keeping the origin greenlet
// around as an owned reference; we need it to call the trace
// function for the switch back into the parent. It was only
// captured at the time the switch actually happened, though,
// so we haven't been keeping an extra reference around this
// whole time.
/* back in the parent */
if (err.status < 0) {
/* start failed badly, restore greenlet state */
this->stack_state = StackState();
this->_main_greenlet.CLEAR();
// CAUTION: This may run arbitrary Python code.
run.CLEAR(); // inner_bootstrap didn't run, we own the reference.
}
// In the success case, the spawned code (inner_bootstrap) will
// take care of decrefing this, so we relinquish ownership so as
// to not double-decref.
run.relinquish_ownership();
return err;
}
void
UserGreenlet::inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run)
{
// The arguments here would be another great place for move.
// As it is, we take them as a reference so that when we clear
// them we clear what's on the stack above us. Do that NOW, and
// without using a C++ RAII object,
// so there's no way that exiting the parent frame can clear it,
// or we clear it unexpectedly. This arises in the context of the
// interpreter shutting down. See https://github.com/python-greenlet/greenlet/issues/325
//PyObject* run = _run.relinquish_ownership();
/* in the new greenlet */
assert(this->thread_state()->borrow_current() == this->_self);
// C++ exceptions cannot propagate to the parent greenlet from
// here. (TODO: Do we need a catch(...) clause, perhaps on the
// function itself? ALl we could do is terminate the program.)
// NOTE: On 32-bit Windows, the call chain is extremely
// important here in ways that are subtle, having to do with
// the depth of the SEH list. The call to restore it MUST NOT
// add a new SEH handler to the list, or we'll restore it to
// the wrong thing.
this->thread_state()->restore_exception_state();
/* stack variables from above are no good and also will not unwind! */
// EXCEPT: That can't be true, we access run, among others, here.
this->stack_state.set_active(); /* running */
// We're about to possibly run Python code again, which
// could switch back/away to/from us, so we need to grab the
// arguments locally.
SwitchingArgs args;
args <<= this->args();
assert(!this->args());
// XXX: We could clear this much earlier, right?
// Or would that introduce the possibility of running Python
// code when we don't want to?
// CAUTION: This may run arbitrary Python code.
this->_run_callable.CLEAR();
// The first switch we need to manually call the trace
// function here instead of in g_switch_finish, because we
// never return there.
if (OwnedObject tracefunc = this->thread_state()->get_tracefunc()) {
OwnedGreenlet trace_origin;
trace_origin = origin_greenlet;
try {
g_calltrace(tracefunc,
args ? mod_globs->event_switch : mod_globs->event_throw,
trace_origin,
this->_self);
}
catch (const PyErrOccurred&) {
/* Turn trace errors into switch throws */
args.CLEAR();
}
}
// We no longer need the origin, it was only here for
// tracing.
// We may never actually exit this stack frame so we need
// to explicitly clear it.
// This could run Python code and switch.
Py_CLEAR(origin_greenlet);
OwnedObject result;
if (!args) {
/* pending exception */
result = NULL;
}
else {
/* call g.run(*args, **kwargs) */
// This could result in further switches
try {
//result = run.PyCall(args.args(), args.kwargs());
// CAUTION: Just invoking this, before the function even
// runs, may cause memory allocations, which may trigger
// GC, which may run arbitrary Python code.
result = OwnedObject::consuming(PyObject_Call(run, args.args().borrow(), args.kwargs().borrow()));
}
catch (...) {
// Unhandled C++ exception!
// If we declare ourselves as noexcept, if we don't catch
// this here, most platforms will just abort() the
// process. But on 64-bit Windows with older versions of
// the C runtime, this can actually corrupt memory and
// just return. We see this when compiling with the
// Windows 7.0 SDK targeting Windows Server 2008, but not
// when using the Appveyor Visual Studio 2019 image. So
// this currently only affects Python 2.7 on Windows 64.
// That is, the tests pass and the runtime aborts
// everywhere else.
//
// However, if we catch it and try to continue with a
// Python error, then all Windows 64 bit platforms corrupt
// memory. So all we can do is manually abort, hopefully
// with a good error message. (Note that the above was
// tested WITHOUT the `/EHr` switch being used at compile
// time, so MSVC may have "optimized" out important
// checking. Using that switch, we may be in a better
// place in terms of memory corruption.) But sometimes it
// can't be caught here at all, which is confusing but not
// terribly surprising; so again, the G_NOEXCEPT_WIN32
// plus "/EHr".
//
// Hopefully the basic C stdlib is still functional enough
// for us to at least print an error.
//
// It gets more complicated than that, though, on some
// platforms, specifically at least Linux/gcc/libstdc++. They use
// an exception to unwind the stack when a background
// thread exits. (See comments about noexcept.) So this
// may not actually represent anything untoward. On those
// platforms we allow throws of this to propagate, or
// attempt to anyway.
# if defined(WIN32) || defined(_WIN32)
Py_FatalError(
"greenlet: Unhandled C++ exception from a greenlet run function. "
"Because memory is likely corrupted, terminating process.");
std::abort();
#else
throw;
#endif
}
}
// These lines may run arbitrary code
args.CLEAR();
Py_CLEAR(run);
if (!result
&& mod_globs->PyExc_GreenletExit.PyExceptionMatches()
&& (this->args())) {
// This can happen, for example, if our only reference
// goes away after we switch back to the parent.
// See test_dealloc_switch_args_not_lost
PyErrPieces clear_error;
result <<= this->args();
result = single_result(result);
}
this->release_args();
this->python_state.did_finish(PyThreadState_GET());
result = g_handle_exit(result);
assert(this->thread_state()->borrow_current() == this->_self);
/* jump back to parent */
this->stack_state.set_inactive(); /* dead */
// TODO: Can we decref some things here? Release our main greenlet
// and maybe parent?
for (Greenlet* parent = this->_parent;
parent;
parent = parent->parent()) {
// We need to somewhere consume a reference to
// the result; in most cases we'll never have control
// back in this stack frame again. Calling
// green_switch actually adds another reference!
// This would probably be clearer with a specific API
// to hand results to the parent.
parent->args() <<= result;
assert(!result);
// The parent greenlet now owns the result; in the
// typical case we'll never get back here to assign to
// result and thus release the reference.
try {
result = parent->g_switch();
}
catch (const PyErrOccurred&) {
// Ignore, keep passing the error on up.
}
/* Return here means switch to parent failed,
* in which case we throw *current* exception
* to the next parent in chain.
*/
assert(!result);
}
/* We ran out of parents, cannot continue */
PyErr_WriteUnraisable(this->self().borrow_o());
Py_FatalError("greenlet: ran out of parent greenlets while propagating exception; "
"cannot continue");
std::abort();
}
void
UserGreenlet::run(const BorrowedObject nrun)
{
if (this->started()) {
throw AttributeError(
"run cannot be set "
"after the start of the greenlet");
}
this->_run_callable = nrun;
}
const OwnedGreenlet
UserGreenlet::parent() const
{
return this->_parent;
}
void
UserGreenlet::parent(const BorrowedObject raw_new_parent)
{
if (!raw_new_parent) {
throw AttributeError("can't delete attribute");
}
BorrowedMainGreenlet main_greenlet_of_new_parent;
BorrowedGreenlet new_parent(raw_new_parent.borrow()); // could
// throw
// TypeError!
for (BorrowedGreenlet p = new_parent; p; p = p->parent()) {
if (p == this->_self) {
throw ValueError("cyclic parent chain");
}
main_greenlet_of_new_parent = p->main_greenlet();
}
if (!main_greenlet_of_new_parent) {
throw ValueError("parent must not be garbage collected");
}
if (this->started()
&& this->_main_greenlet != main_greenlet_of_new_parent) {
throw ValueError("parent cannot be on a different thread");
}
this->_parent = new_parent;
}
void
UserGreenlet::murder_in_place()
{
this->_main_greenlet.CLEAR();
Greenlet::murder_in_place();
}
bool
UserGreenlet::belongs_to_thread(const ThreadState* thread_state) const
{
return Greenlet::belongs_to_thread(thread_state) && this->_main_greenlet == thread_state->borrow_main_greenlet();
}
int
UserGreenlet::tp_traverse(visitproc visit, void* arg)
{
Py_VISIT(this->_parent.borrow_o());
Py_VISIT(this->_main_greenlet.borrow_o());
Py_VISIT(this->_run_callable.borrow_o());
return Greenlet::tp_traverse(visit, arg);
}
int
UserGreenlet::tp_clear()
{
Greenlet::tp_clear();
this->_parent.CLEAR();
this->_main_greenlet.CLEAR();
this->_run_callable.CLEAR();
return 0;
}
UserGreenlet::ParentIsCurrentGuard::ParentIsCurrentGuard(UserGreenlet* p,
const ThreadState& thread_state)
: oldparent(p->_parent),
greenlet(p)
{
p->_parent = thread_state.get_current();
}
UserGreenlet::ParentIsCurrentGuard::~ParentIsCurrentGuard()
{
this->greenlet->_parent = oldparent;
oldparent.CLEAR();
}
}; //namespace greenlet

View file

@ -1,71 +0,0 @@
# -*- coding: utf-8 -*-
"""
The root of the greenlet package.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
__all__ = [
'__version__',
'_C_API',
'GreenletExit',
'error',
'getcurrent',
'greenlet',
'gettrace',
'settrace',
]
# pylint:disable=no-name-in-module
###
# Metadata
###
__version__ = '3.0.3'
from ._greenlet import _C_API # pylint:disable=no-name-in-module
###
# Exceptions
###
from ._greenlet import GreenletExit
from ._greenlet import error
###
# greenlets
###
from ._greenlet import getcurrent
from ._greenlet import greenlet
###
# tracing
###
try:
from ._greenlet import gettrace
from ._greenlet import settrace
except ImportError:
# Tracing wasn't supported.
# XXX: The option to disable it was removed in 1.0,
# so this branch should be dead code.
pass
###
# Constants
# These constants aren't documented and aren't recommended.
# In 1.0, USE_GC and USE_TRACING are always true, and USE_CONTEXT_VARS
# is the same as ``sys.version_info[:2] >= 3.7``
###
from ._greenlet import GREENLET_USE_CONTEXT_VARS # pylint:disable=unused-import
from ._greenlet import GREENLET_USE_GC # pylint:disable=unused-import
from ._greenlet import GREENLET_USE_TRACING # pylint:disable=unused-import
# Controlling the use of the gc module. Provisional API for this greenlet
# implementation in 2.0.
from ._greenlet import CLOCKS_PER_SEC # pylint:disable=unused-import
from ._greenlet import enable_optional_cleanup # pylint:disable=unused-import
from ._greenlet import get_clocks_used_doing_optional_cleanup # pylint:disable=unused-import
# Other APIS in the _greenlet module are for test support.

File diff suppressed because it is too large Load diff

View file

@ -1,164 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
/* Greenlet object interface */
#ifndef Py_GREENLETOBJECT_H
#define Py_GREENLETOBJECT_H
#include <Python.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is deprecated and undocumented. It does not change. */
#define GREENLET_VERSION "1.0.0"
#ifndef GREENLET_MODULE
#define implementation_ptr_t void*
#endif
typedef struct _greenlet {
PyObject_HEAD
PyObject* weakreflist;
PyObject* dict;
implementation_ptr_t pimpl;
} PyGreenlet;
#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type))
/* C API functions */
/* Total number of symbols that are exported */
#define PyGreenlet_API_pointers 12
#define PyGreenlet_Type_NUM 0
#define PyExc_GreenletError_NUM 1
#define PyExc_GreenletExit_NUM 2
#define PyGreenlet_New_NUM 3
#define PyGreenlet_GetCurrent_NUM 4
#define PyGreenlet_Throw_NUM 5
#define PyGreenlet_Switch_NUM 6
#define PyGreenlet_SetParent_NUM 7
#define PyGreenlet_MAIN_NUM 8
#define PyGreenlet_STARTED_NUM 9
#define PyGreenlet_ACTIVE_NUM 10
#define PyGreenlet_GET_PARENT_NUM 11
#ifndef GREENLET_MODULE
/* This section is used by modules that uses the greenlet C API */
static void** _PyGreenlet_API = NULL;
# define PyGreenlet_Type \
(*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM])
# define PyExc_GreenletError \
((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM])
# define PyExc_GreenletExit \
((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM])
/*
* PyGreenlet_New(PyObject *args)
*
* greenlet.greenlet(run, parent=None)
*/
# define PyGreenlet_New \
(*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \
_PyGreenlet_API[PyGreenlet_New_NUM])
/*
* PyGreenlet_GetCurrent(void)
*
* greenlet.getcurrent()
*/
# define PyGreenlet_GetCurrent \
(*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM])
/*
* PyGreenlet_Throw(
* PyGreenlet *greenlet,
* PyObject *typ,
* PyObject *val,
* PyObject *tb)
*
* g.throw(...)
*/
# define PyGreenlet_Throw \
(*(PyObject * (*)(PyGreenlet * self, \
PyObject * typ, \
PyObject * val, \
PyObject * tb)) \
_PyGreenlet_API[PyGreenlet_Throw_NUM])
/*
* PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args)
*
* g.switch(*args, **kwargs)
*/
# define PyGreenlet_Switch \
(*(PyObject * \
(*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \
_PyGreenlet_API[PyGreenlet_Switch_NUM])
/*
* PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent)
*
* g.parent = new_parent
*/
# define PyGreenlet_SetParent \
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
_PyGreenlet_API[PyGreenlet_SetParent_NUM])
/*
* PyGreenlet_GetParent(PyObject* greenlet)
*
* return greenlet.parent;
*
* This could return NULL even if there is no exception active.
* If it does not return NULL, you are responsible for decrementing the
* reference count.
*/
# define PyGreenlet_GetParent \
(*(PyGreenlet* (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_GET_PARENT_NUM])
/*
* deprecated, undocumented alias.
*/
# define PyGreenlet_GET_PARENT PyGreenlet_GetParent
# define PyGreenlet_MAIN \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_MAIN_NUM])
# define PyGreenlet_STARTED \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_STARTED_NUM])
# define PyGreenlet_ACTIVE \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_ACTIVE_NUM])
/* Macro that imports greenlet and initializes C API */
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
keep the older definition to be sure older code that might have a copy of
the header still works. */
# define PyGreenlet_Import() \
{ \
_PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \
}
#endif /* GREENLET_MODULE */
#ifdef __cplusplus
}
#endif
#endif /* !Py_GREENLETOBJECT_H */

View file

@ -1,63 +0,0 @@
#ifndef GREENLET_ALLOCATOR_HPP
#define GREENLET_ALLOCATOR_HPP
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <memory>
#include "greenlet_compiler_compat.hpp"
namespace greenlet
{
// This allocator is stateless; all instances are identical.
// It can *ONLY* be used when we're sure we're holding the GIL
// (Python's allocators require the GIL).
template <class T>
struct PythonAllocator : public std::allocator<T> {
PythonAllocator(const PythonAllocator& UNUSED(other))
: std::allocator<T>()
{
}
PythonAllocator(const std::allocator<T> other)
: std::allocator<T>(other)
{}
template <class U>
PythonAllocator(const std::allocator<U>& other)
: std::allocator<T>(other)
{
}
PythonAllocator() : std::allocator<T>() {}
T* allocate(size_t number_objects, const void* UNUSED(hint)=0)
{
void* p;
if (number_objects == 1)
p = PyObject_Malloc(sizeof(T));
else
p = PyMem_Malloc(sizeof(T) * number_objects);
return static_cast<T*>(p);
}
void deallocate(T* t, size_t n)
{
void* p = t;
if (n == 1) {
PyObject_Free(p);
}
else
PyMem_Free(p);
}
// This member is deprecated in C++17 and removed in C++20
template< class U >
struct rebind {
typedef PythonAllocator<U> other;
};
};
}
#endif

View file

@ -1,95 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
#ifndef GREENLET_COMPILER_COMPAT_HPP
#define GREENLET_COMPILER_COMPAT_HPP
/**
* Definitions to aid with compatibility with different compilers.
*
* .. caution:: Use extreme care with noexcept.
* Some compilers and runtimes, specifically gcc/libgcc/libstdc++ on
* Linux, implement stack unwinding by throwing an uncatchable
* exception, one that specifically does not appear to be an active
* exception to the rest of the runtime. If this happens while we're in a noexcept function,
* we have violated our dynamic exception contract, and so the runtime
* will call std::terminate(), which kills the process with the
* unhelpful message "terminate called without an active exception".
*
* This has happened in this scenario: A background thread is running
* a greenlet that has made a native call and released the GIL.
* Meanwhile, the main thread finishes and starts shutting down the
* interpreter. When the background thread is scheduled again and
* attempts to obtain the GIL, it notices that the interpreter is
* exiting and calls ``pthread_exit()``. This in turn starts to unwind
* the stack by throwing that exception. But we had the ``PyCall``
* functions annotated as noexcept, so the runtime terminated us.
*
* #2 0x00007fab26fec2b7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6
* #3 0x00007fab26febb3c in __gxx_personality_v0 () from /lib/x86_64-linux-gnu/libstdc++.so.6
* #4 0x00007fab26f34de6 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1
* #6 0x00007fab276a34c6 in __GI___pthread_unwind at ./nptl/unwind.c:130
* #7 0x00007fab2769bd3a in __do_cancel () at ../sysdeps/nptl/pthreadP.h:280
* #8 __GI___pthread_exit (value=value@entry=0x0) at ./nptl/pthread_exit.c:36
* #9 0x000000000052e567 in PyThread_exit_thread () at ../Python/thread_pthread.h:370
* #10 0x00000000004d60b5 in take_gil at ../Python/ceval_gil.h:224
* #11 0x00000000004d65f9 in PyEval_RestoreThread at ../Python/ceval.c:467
* #12 0x000000000060cce3 in setipaddr at ../Modules/socketmodule.c:1203
* #13 0x00000000006101cd in socket_gethostbyname
*/
#include <cstdint>
# if defined(__clang__)
# define G_FP_TMPL_STATIC static
# else
// GCC has no problem allowing static function pointers, but emits
// tons of warnings about "whose type uses the anonymous namespace [-Wsubobject-linkage]"
# define G_FP_TMPL_STATIC
# endif
# define G_NO_COPIES_OF_CLS(Cls) private: \
Cls(const Cls& other) = delete; \
Cls& operator=(const Cls& other) = delete
# define G_NO_ASSIGNMENT_OF_CLS(Cls) private: \
Cls& operator=(const Cls& other) = delete
# define G_NO_COPY_CONSTRUCTOR_OF_CLS(Cls) private: \
Cls(const Cls& other) = delete;
// CAUTION: MSVC is stupidly picky:
//
// "The compiler ignores, without warning, any __declspec keywords
// placed after * or & and in front of the variable identifier in a
// declaration."
// (https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-160)
//
// So pointer return types must be handled differently (because of the
// trailing *), or you get inscrutable compiler warnings like "error
// C2059: syntax error: ''"
//
// In C++ 11, there is a standard syntax for attributes, and
// GCC defines an attribute to use with this: [[gnu:noinline]].
// In the future, this is expected to become standard.
#if defined(__GNUC__) || defined(__clang__)
/* We used to check for GCC 4+ or 3.4+, but those compilers are
laughably out of date. Just assume they support it. */
# define GREENLET_NOINLINE(name) __attribute__((noinline)) name
# define GREENLET_NOINLINE_P(rtype, name) rtype __attribute__((noinline)) name
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
#elif defined(_MSC_VER)
/* We used to check for && (_MSC_VER >= 1300) but that's also out of date. */
# define GREENLET_NOINLINE(name) __declspec(noinline) name
# define GREENLET_NOINLINE_P(rtype, name) __declspec(noinline) rtype name
# define UNUSED(x) UNUSED_ ## x
#endif
#if defined(_MSC_VER)
# define G_NOEXCEPT_WIN32 noexcept
#else
# define G_NOEXCEPT_WIN32
#endif
#endif

View file

@ -1,172 +0,0 @@
#ifndef GREENLET_CPYTHON_ADD_PENDING_HPP
#define GREENLET_CPYTHON_ADD_PENDING_HPP
#if (PY_VERSION_HEX >= 0x30800A0 && PY_VERSION_HEX < 0x3090000) && !(defined(_WIN32) || defined(WIN32))
// XXX: From Python 3.8a3 [1] up until Python 3.9a6 [2][3],
// ``Py_AddPendingCall`` would try to produce a Python exception if
// the interpreter was in the beginning of shutting down when this
// function is called. However, ``Py_AddPendingCall`` doesn't require
// the GIL, and we are absolutely not holding it when we make that
// call. That means that trying to create the Python exception is
// using the C API in an undefined state; here the C API detects this
// and aborts the process with an error ("Fatal Python error: Python
// memory allocator called without holding the GIL": Add ->
// PyErr_SetString -> PyUnicode_New -> PyObject_Malloc). This arises
// (obviously) in multi-threaded programs and happens if one thread is
// exiting and cleaning up its thread-local data while the other
// thread is trying to shut down the interpreter. A crash on shutdown
// is still a crash and could result in data loss (e.g., daemon
// threads are still running, pending signal handlers may be present,
// buffers may not be flushed, there may be __del__ that need run,
// etc), so we have to work around it.
//
// Of course, we can (and do) check for whether the interpreter is
// shutting down before calling ``Py_AddPendingCall``, but that's a
// race condition since we don't hold the GIL, and so we may not
// actually get the right answer. Plus, ``Py_FinalizeEx`` actually
// calls ``_Py_FinishPendingCalls`` (which sets the pending->finishing
// flag, which is used to gate creating the exceptioen) *before*
// publishing any other data that would let us detect the shutdown
// (such as runtime->finalizing). So that point is moot.
//
// Our solution for those versions is to inline the same code, without
// the problematic bit that sets the exception. Unfortunately, all of
// the structure definitions are private/opaque, *and* we can't
// actually count on being able to include their definitions from
// ``internal/pycore_*``, because on some platforms those header files
// are incomplete (i.e., on macOS with macports 3.8, the includes are
// fine, but on Ubuntu jammy with 3.8 from ppa:deadsnakes or GitHub
// Actions 3.8 (I think it's Ubuntu 18.04), they con't be used; at
// least, I couldn't get them to work). So we need to define the
// structures and _PyRuntime data member ourself. Yet more
// unfortunately, _PyRuntime won't link on Windows, so we can only do
// this on other platforms.
//
// [1] https://github.com/python/cpython/commit/842a2f07f2f08a935ef470bfdaeef40f87490cfc
// [2] https://github.com/python/cpython/commit/cfc3c2f8b34d3864717ab584c5b6c260014ba55a
// [3] https://github.com/python/cpython/issues/81308
# define GREENLET_BROKEN_PY_ADD_PENDING 1
// When defining these structures, the important thing is to get
// binary compatibility, i.e., structure layout. For that, we only
// need to define fields up to the ones we use; after that they're
// irrelevant UNLESS the structure is included in another structure
// *before* the structure we're interested in --- in that case, it
// must be complete. Ellipsis indicate elided trailing members.
// Pointer types are changed to void* to keep from having to define
// more structures.
// From "internal/pycore_atomic.h"
// There are several different definitions of this, including the
// plain ``int`` version, a ``volatile int`` and an ``_Atomic int``
// I don't think any of those change the size/layout.
typedef struct _Py_atomic_int {
volatile int _value;
} _Py_atomic_int;
// This needs too much infrastructure, so we just do a regular store.
#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \
(ATOMIC_VAL)->_value = NEW_VAL
// From "internal/pycore_pymem.h"
#define NUM_GENERATIONS 3
struct gc_generation {
PyGC_Head head; // We already have this defined.
int threshold;
int count;
};
struct gc_generation_stats {
Py_ssize_t collections;
Py_ssize_t collected;
Py_ssize_t uncollectable;
};
struct _gc_runtime_state {
void *trash_delete_later;
int trash_delete_nesting;
int enabled;
int debug;
struct gc_generation generations[NUM_GENERATIONS];
void *generation0;
struct gc_generation permanent_generation;
struct gc_generation_stats generation_stats[NUM_GENERATIONS];
int collecting;
void *garbage;
void *callbacks;
Py_ssize_t long_lived_total;
Py_ssize_t long_lived_pending;
};
// From "internal/pycore_pystate.h"
struct _pending_calls {
int finishing;
PyThread_type_lock lock;
_Py_atomic_int calls_to_do;
int async_exc;
#define NPENDINGCALLS 32
struct {
int (*func)(void *);
void *arg;
} calls[NPENDINGCALLS];
int first;
int last;
};
struct _ceval_runtime_state {
int recursion_limit;
int tracing_possible;
_Py_atomic_int eval_breaker;
_Py_atomic_int gil_drop_request;
struct _pending_calls pending;
// ...
};
typedef struct pyruntimestate {
int preinitializing;
int preinitialized;
int core_initialized;
int initialized;
void *finalizing;
struct pyinterpreters {
PyThread_type_lock mutex;
void *head;
void *main;
int64_t next_id;
} interpreters;
// XXX Remove this field once we have a tp_* slot.
struct _xidregistry {
PyThread_type_lock mutex;
void *head;
} xidregistry;
unsigned long main_thread;
#define NEXITFUNCS 32
void (*exitfuncs[NEXITFUNCS])(void);
int nexitfuncs;
struct _gc_runtime_state gc;
struct _ceval_runtime_state ceval;
// ...
} _PyRuntimeState;
#define SIGNAL_PENDING_CALLS(ceval) \
do { \
_Py_atomic_store_relaxed(&(ceval)->pending.calls_to_do, 1); \
_Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \
} while (0)
extern _PyRuntimeState _PyRuntime;
#else
# define GREENLET_BROKEN_PY_ADD_PENDING 0
#endif
#endif

View file

@ -1,127 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
#ifndef GREENLET_CPYTHON_COMPAT_H
#define GREENLET_CPYTHON_COMPAT_H
/**
* Helpers for compatibility with multiple versions of CPython.
*/
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#if PY_VERSION_HEX >= 0x30A00B1
# define GREENLET_PY310 1
/*
Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member.
See https://github.com/python/cpython/pull/25276
We have to save and restore this as well.
*/
# define GREENLET_USE_CFRAME 1
#else
# define GREENLET_USE_CFRAME 0
# define GREENLET_PY310 0
#endif
#if PY_VERSION_HEX >= 0x30B00A4
/*
Greenlet won't compile on anything older than Python 3.11 alpha 4 (see
https://bugs.python.org/issue46090). Summary of breaking internal changes:
- Python 3.11 alpha 1 changed how frame objects are represented internally.
- https://github.com/python/cpython/pull/30122
- Python 3.11 alpha 3 changed how recursion limits are stored.
- https://github.com/python/cpython/pull/29524
- Python 3.11 alpha 4 changed how exception state is stored. It also includes a
change to help greenlet save and restore the interpreter frame "data stack".
- https://github.com/python/cpython/pull/30122
- https://github.com/python/cpython/pull/30234
*/
# define GREENLET_PY311 1
#else
# define GREENLET_PY311 0
#endif
#if PY_VERSION_HEX >= 0x30C0000
# define GREENLET_PY312 1
#else
# define GREENLET_PY312 0
#endif
#ifndef Py_SET_REFCNT
/* Py_REFCNT and Py_SIZE macros are converted to functions
https://bugs.python.org/issue39573 */
# define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt)
#endif
#ifndef _Py_DEC_REFTOTAL
/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by:
https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924
The symbol we use to replace it was removed by at least 3.12.
*/
# ifdef Py_REF_DEBUG
# if GREENLET_PY312
# define _Py_DEC_REFTOTAL
# else
# define _Py_DEC_REFTOTAL _Py_RefTotal--
# endif
# else
# define _Py_DEC_REFTOTAL
# endif
#endif
// Define these flags like Cython does if we're on an old version.
#ifndef Py_TPFLAGS_CHECKTYPES
#define Py_TPFLAGS_CHECKTYPES 0
#endif
#ifndef Py_TPFLAGS_HAVE_INDEX
#define Py_TPFLAGS_HAVE_INDEX 0
#endif
#ifndef Py_TPFLAGS_HAVE_NEWBUFFER
#define Py_TPFLAGS_HAVE_NEWBUFFER 0
#endif
#ifndef Py_TPFLAGS_HAVE_VERSION_TAG
#define Py_TPFLAGS_HAVE_VERSION_TAG 0
#endif
#define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC
#if PY_VERSION_HEX < 0x03090000
// The official version only became available in 3.9
# define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o)
#endif
// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
{
tstate->tracing++;
#if PY_VERSION_HEX >= 0x030A00A1
tstate->cframe->use_tracing = 0;
#else
tstate->use_tracing = 0;
#endif
}
#endif
// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
{
tstate->tracing--;
int use_tracing = (tstate->c_tracefunc != NULL
|| tstate->c_profilefunc != NULL);
#if PY_VERSION_HEX >= 0x030A00A1
tstate->cframe->use_tracing = use_tracing;
#else
tstate->use_tracing = use_tracing;
#endif
}
#endif
#endif /* GREENLET_CPYTHON_COMPAT_H */

View file

@ -1,150 +0,0 @@
#ifndef GREENLET_EXCEPTIONS_HPP
#define GREENLET_EXCEPTIONS_HPP
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdexcept>
#include <string>
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-function"
#endif
namespace greenlet {
class PyErrOccurred : public std::runtime_error
{
public:
// CAUTION: In debug builds, may run arbitrary Python code.
static const PyErrOccurred
from_current()
{
assert(PyErr_Occurred());
#ifndef NDEBUG
// This is not exception safe, and
// not necessarily safe in general (what if it switches?)
// But we only do this in debug mode, where we are in
// tight control of what exceptions are getting raised and
// can prevent those issues.
// You can't call PyObject_Str with a pending exception.
PyObject* typ;
PyObject* val;
PyObject* tb;
PyErr_Fetch(&typ, &val, &tb);
PyObject* typs = PyObject_Str(typ);
PyObject* vals = PyObject_Str(val ? val : typ);
const char* typ_msg = PyUnicode_AsUTF8(typs);
const char* val_msg = PyUnicode_AsUTF8(vals);
PyErr_Restore(typ, val, tb);
std::string msg(typ_msg);
msg += ": ";
msg += val_msg;
PyErrOccurred ex(msg);
Py_XDECREF(typs);
Py_XDECREF(vals);
return ex;
#else
return PyErrOccurred();
#endif
}
PyErrOccurred() : std::runtime_error("")
{
assert(PyErr_Occurred());
}
PyErrOccurred(const std::string& msg) : std::runtime_error(msg)
{
assert(PyErr_Occurred());
}
PyErrOccurred(PyObject* exc_kind, const char* const msg)
: std::runtime_error(msg)
{
PyErr_SetString(exc_kind, msg);
}
PyErrOccurred(PyObject* exc_kind, const std::string msg)
: std::runtime_error(msg)
{
// This copies the c_str, so we don't have any lifetime
// issues to worry about.
PyErr_SetString(exc_kind, msg.c_str());
}
};
class TypeError : public PyErrOccurred
{
public:
TypeError(const char* const what)
: PyErrOccurred(PyExc_TypeError, what)
{
}
TypeError(const std::string what)
: PyErrOccurred(PyExc_TypeError, what)
{
}
};
class ValueError : public PyErrOccurred
{
public:
ValueError(const char* const what)
: PyErrOccurred(PyExc_ValueError, what)
{
}
};
class AttributeError : public PyErrOccurred
{
public:
AttributeError(const char* const what)
: PyErrOccurred(PyExc_AttributeError, what)
{
}
};
/**
* Calls `Py_FatalError` when constructed, so you can't actually
* throw this. It just makes static analysis easier.
*/
class PyFatalError : public std::runtime_error
{
public:
PyFatalError(const char* const msg)
: std::runtime_error(msg)
{
Py_FatalError(msg);
}
};
static inline PyObject*
Require(PyObject* p, const std::string& msg="")
{
if (!p) {
throw PyErrOccurred(msg);
}
return p;
};
static inline void
Require(const int retval)
{
if (retval < 0) {
throw PyErrOccurred();
}
};
};
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif

View file

@ -1,805 +0,0 @@
#ifndef GREENLET_GREENLET_HPP
#define GREENLET_GREENLET_HPP
/*
* Declarations of the core data structures.
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "greenlet_compiler_compat.hpp"
#include "greenlet_refs.hpp"
#include "greenlet_cpython_compat.hpp"
#include "greenlet_allocator.hpp"
using greenlet::refs::OwnedObject;
using greenlet::refs::OwnedGreenlet;
using greenlet::refs::OwnedMainGreenlet;
using greenlet::refs::BorrowedGreenlet;
#if PY_VERSION_HEX < 0x30B00A6
# define _PyCFrame CFrame
# define _PyInterpreterFrame _interpreter_frame
#endif
#if GREENLET_PY312
# include "internal/pycore_frame.h"
#endif
// XXX: TODO: Work to remove all virtual functions
// for speed of calling and size of objects (no vtable).
// One pattern is the Curiously Recurring Template
namespace greenlet
{
class ExceptionState
{
private:
G_NO_COPIES_OF_CLS(ExceptionState);
// Even though these are borrowed objects, we actually own
// them, when they're not null.
// XXX: Express that in the API.
private:
_PyErr_StackItem* exc_info;
_PyErr_StackItem exc_state;
public:
ExceptionState();
void operator<<(const PyThreadState *const tstate) noexcept;
void operator>>(PyThreadState* tstate) noexcept;
void clear() noexcept;
int tp_traverse(visitproc visit, void* arg) noexcept;
void tp_clear() noexcept;
};
template<typename T>
void operator<<(const PyThreadState *const tstate, T& exc);
class PythonStateContext
{
protected:
greenlet::refs::OwnedContext _context;
public:
inline const greenlet::refs::OwnedContext& context() const
{
return this->_context;
}
inline greenlet::refs::OwnedContext& context()
{
return this->_context;
}
inline void tp_clear()
{
this->_context.CLEAR();
}
template<typename T>
inline static PyObject* context(T* tstate)
{
return tstate->context;
}
template<typename T>
inline static void context(T* tstate, PyObject* new_context)
{
tstate->context = new_context;
tstate->context_ver++;
}
};
class SwitchingArgs;
class PythonState : public PythonStateContext
{
public:
typedef greenlet::refs::OwnedReference<struct _frame> OwnedFrame;
private:
G_NO_COPIES_OF_CLS(PythonState);
// We own this if we're suspended (although currently we don't
// tp_traverse into it; that's a TODO). If we're running, it's
// empty. If we get deallocated and *still* have a frame, it
// won't be reachable from the place that normally decref's
// it, so we need to do it (hence owning it).
OwnedFrame _top_frame;
#if GREENLET_USE_CFRAME
_PyCFrame* cframe;
int use_tracing;
#endif
#if GREENLET_PY312
int py_recursion_depth;
int c_recursion_depth;
#else
int recursion_depth;
#endif
int trash_delete_nesting;
#if GREENLET_PY311
_PyInterpreterFrame* current_frame;
_PyStackChunk* datastack_chunk;
PyObject** datastack_top;
PyObject** datastack_limit;
#endif
// The PyInterpreterFrame list on 3.12+ contains some entries that are
// on the C stack, which can't be directly accessed while a greenlet is
// suspended. In order to keep greenlet gr_frame introspection working,
// we adjust stack switching to rewrite the interpreter frame list
// to skip these C-stack frames; we call this "exposing" the greenlet's
// frames because it makes them valid to work with in Python. Then when
// the greenlet is resumed we need to remember to reverse the operation
// we did. The C-stack frames are "entry frames" which are a low-level
// interpreter detail; they're not needed for introspection, but do
// need to be present for the eval loop to work.
void unexpose_frames();
public:
PythonState();
// You can use this for testing whether we have a frame
// or not. It returns const so they can't modify it.
const OwnedFrame& top_frame() const noexcept;
inline void operator<<(const PyThreadState *const tstate) noexcept;
inline void operator>>(PyThreadState* tstate) noexcept;
void clear() noexcept;
int tp_traverse(visitproc visit, void* arg, bool visit_top_frame) noexcept;
void tp_clear(bool own_top_frame) noexcept;
void set_initial_state(const PyThreadState* const tstate) noexcept;
#if GREENLET_USE_CFRAME
void set_new_cframe(_PyCFrame& frame) noexcept;
#endif
inline void may_switch_away() noexcept;
inline void will_switch_from(PyThreadState *const origin_tstate) noexcept;
void did_finish(PyThreadState* tstate) noexcept;
};
class StackState
{
// By having only plain C (POD) members, no virtual functions
// or bases, we get a trivial assignment operator generated
// for us. However, that's not safe since we do manage memory.
// So we declare an assignment operator that only works if we
// don't have any memory allocated. (We don't use
// std::shared_ptr for reference counting just to keep this
// object small)
private:
char* _stack_start;
char* stack_stop;
char* stack_copy;
intptr_t _stack_saved;
StackState* stack_prev;
inline int copy_stack_to_heap_up_to(const char* const stop) noexcept;
inline void free_stack_copy() noexcept;
public:
/**
* Creates a started, but inactive, state, using *current*
* as the previous.
*/
StackState(void* mark, StackState& current);
/**
* Creates an inactive, unstarted, state.
*/
StackState();
~StackState();
StackState(const StackState& other);
StackState& operator=(const StackState& other);
inline void copy_heap_to_stack(const StackState& current) noexcept;
inline int copy_stack_to_heap(char* const stackref, const StackState& current) noexcept;
inline bool started() const noexcept;
inline bool main() const noexcept;
inline bool active() const noexcept;
inline void set_active() noexcept;
inline void set_inactive() noexcept;
inline intptr_t stack_saved() const noexcept;
inline char* stack_start() const noexcept;
static inline StackState make_main() noexcept;
#ifdef GREENLET_USE_STDIO
friend std::ostream& operator<<(std::ostream& os, const StackState& s);
#endif
// Fill in [dest, dest + n) with the values that would be at
// [src, src + n) while this greenlet is running. This is like memcpy
// except that if the greenlet is suspended it accounts for the portion
// of the greenlet's stack that was spilled to the heap. `src` may
// be on this greenlet's stack, or on the heap, but not on a different
// greenlet's stack.
void copy_from_stack(void* dest, const void* src, size_t n) const;
};
#ifdef GREENLET_USE_STDIO
std::ostream& operator<<(std::ostream& os, const StackState& s);
#endif
class SwitchingArgs
{
private:
G_NO_ASSIGNMENT_OF_CLS(SwitchingArgs);
// If args and kwargs are both false (NULL), this is a *throw*, not a
// switch. PyErr_... must have been called already.
OwnedObject _args;
OwnedObject _kwargs;
public:
SwitchingArgs()
{}
SwitchingArgs(const OwnedObject& args, const OwnedObject& kwargs)
: _args(args),
_kwargs(kwargs)
{}
SwitchingArgs(const SwitchingArgs& other)
: _args(other._args),
_kwargs(other._kwargs)
{}
const OwnedObject& args()
{
return this->_args;
}
const OwnedObject& kwargs()
{
return this->_kwargs;
}
/**
* Moves ownership from the argument to this object.
*/
SwitchingArgs& operator<<=(SwitchingArgs& other)
{
if (this != &other) {
this->_args = other._args;
this->_kwargs = other._kwargs;
other.CLEAR();
}
return *this;
}
/**
* Acquires ownership of the argument (consumes the reference).
*/
SwitchingArgs& operator<<=(PyObject* args)
{
this->_args = OwnedObject::consuming(args);
this->_kwargs.CLEAR();
return *this;
}
/**
* Acquires ownership of the argument.
*
* Sets the args to be the given value; clears the kwargs.
*/
SwitchingArgs& operator<<=(OwnedObject& args)
{
assert(&args != &this->_args);
this->_args = args;
this->_kwargs.CLEAR();
args.CLEAR();
return *this;
}
explicit operator bool() const noexcept
{
return this->_args || this->_kwargs;
}
inline void CLEAR()
{
this->_args.CLEAR();
this->_kwargs.CLEAR();
}
const std::string as_str() const noexcept
{
return PyUnicode_AsUTF8(
OwnedObject::consuming(
PyUnicode_FromFormat(
"SwitchingArgs(args=%R, kwargs=%R)",
this->_args.borrow(),
this->_kwargs.borrow()
)
).borrow()
);
}
};
class ThreadState;
class UserGreenlet;
class MainGreenlet;
class Greenlet
{
private:
G_NO_COPIES_OF_CLS(Greenlet);
private:
// XXX: Work to remove these.
friend class ThreadState;
friend class UserGreenlet;
friend class MainGreenlet;
protected:
ExceptionState exception_state;
SwitchingArgs switch_args;
StackState stack_state;
PythonState python_state;
Greenlet(PyGreenlet* p, const StackState& initial_state);
public:
Greenlet(PyGreenlet* p);
virtual ~Greenlet();
const OwnedObject context() const;
// You MUST call this _very_ early in the switching process to
// prepare anything that may need prepared. This might perform
// garbage collections or otherwise run arbitrary Python code.
//
// One specific use of it is for Python 3.11+, preventing
// running arbitrary code at unsafe times. See
// PythonState::may_switch_away().
inline void may_switch_away()
{
this->python_state.may_switch_away();
}
inline void context(refs::BorrowedObject new_context);
inline SwitchingArgs& args()
{
return this->switch_args;
}
virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0;
inline intptr_t stack_saved() const noexcept
{
return this->stack_state.stack_saved();
}
// This is used by the macro SLP_SAVE_STATE to compute the
// difference in stack sizes. It might be nice to handle the
// computation ourself, but the type of the result
// varies by platform, so doing it in the macro is the
// simplest way.
inline const char* stack_start() const noexcept
{
return this->stack_state.stack_start();
}
virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state);
virtual OwnedObject g_switch() = 0;
/**
* Force the greenlet to appear dead. Used when it's not
* possible to throw an exception into a greenlet anymore.
*
* This losses access to the thread state and the main greenlet.
*/
virtual void murder_in_place();
/**
* Called when somebody notices we were running in a dead
* thread to allow cleaning up resources (because we can't
* raise GreenletExit into it anymore).
* This is very similar to ``murder_in_place()``, except that
* it DOES NOT lose the main greenlet or thread state.
*/
inline void deactivate_and_free();
// Called when some thread wants to deallocate a greenlet
// object.
// The thread may or may not be the same thread the greenlet
// was running in.
// The thread state will be null if the thread the greenlet
// was running in was known to have exited.
void deallocing_greenlet_in_thread(const ThreadState* current_state);
// Must be called on 3.12+ before exposing a suspended greenlet's
// frames to user code. This rewrites the linked list of interpreter
// frames to skip the ones that are being stored on the C stack (which
// can't be safely accessed while the greenlet is suspended because
// that stack space might be hosting a different greenlet), and
// sets PythonState::frames_were_exposed so we remember to restore
// the original list before resuming the greenlet. The C-stack frames
// are a low-level interpreter implementation detail; while they're
// important to the bytecode eval loop, they're superfluous for
// introspection purposes.
void expose_frames();
// TODO: Figure out how to make these non-public.
inline void slp_restore_state() noexcept;
inline int slp_save_state(char *const stackref) noexcept;
inline bool is_currently_running_in_some_thread() const;
virtual bool belongs_to_thread(const ThreadState* state) const;
inline bool started() const
{
return this->stack_state.started();
}
inline bool active() const
{
return this->stack_state.active();
}
inline bool main() const
{
return this->stack_state.main();
}
virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0;
virtual const OwnedGreenlet parent() const = 0;
virtual void parent(const refs::BorrowedObject new_parent) = 0;
inline const PythonState::OwnedFrame& top_frame()
{
return this->python_state.top_frame();
}
virtual const OwnedObject& run() const = 0;
virtual void run(const refs::BorrowedObject nrun) = 0;
virtual int tp_traverse(visitproc visit, void* arg);
virtual int tp_clear();
// Return the thread state that the greenlet is running in, or
// null if the greenlet is not running or the thread is known
// to have exited.
virtual ThreadState* thread_state() const noexcept = 0;
// Return true if the greenlet is known to have been running
// (active) in a thread that has now exited.
virtual bool was_running_in_dead_thread() const noexcept = 0;
// Return a borrowed greenlet that is the Python object
// this object represents.
virtual BorrowedGreenlet self() const noexcept = 0;
// For testing. If this returns true, we should pretend that
// slp_switch() failed.
virtual bool force_slp_switch_error() const noexcept;
protected:
inline void release_args();
// The functions that must not be inlined are declared virtual.
// We also mark them as protected, not private, so that the
// compiler is forced to call them through a function pointer.
// (A sufficiently smart compiler could directly call a private
// virtual function since it can never be overridden in a
// subclass).
// Also TODO: Switch away from integer error codes and to enums,
// or throw exceptions when possible.
struct switchstack_result_t
{
int status;
Greenlet* the_new_current_greenlet;
OwnedGreenlet origin_greenlet;
switchstack_result_t()
: status(0),
the_new_current_greenlet(nullptr)
{}
switchstack_result_t(int err)
: status(err),
the_new_current_greenlet(nullptr)
{}
switchstack_result_t(int err, Greenlet* state, OwnedGreenlet& origin)
: status(err),
the_new_current_greenlet(state),
origin_greenlet(origin)
{
}
switchstack_result_t(int err, Greenlet* state, const BorrowedGreenlet& origin)
: status(err),
the_new_current_greenlet(state),
origin_greenlet(origin)
{
}
switchstack_result_t(const switchstack_result_t& other)
: status(other.status),
the_new_current_greenlet(other.the_new_current_greenlet),
origin_greenlet(other.origin_greenlet)
{}
switchstack_result_t& operator=(const switchstack_result_t& other)
{
this->status = other.status;
this->the_new_current_greenlet = other.the_new_current_greenlet;
this->origin_greenlet = other.origin_greenlet;
return *this;
}
};
OwnedObject on_switchstack_or_initialstub_failure(
Greenlet* target,
const switchstack_result_t& err,
const bool target_was_me=false,
const bool was_initial_stub=false);
// Returns the previous greenlet we just switched away from.
virtual OwnedGreenlet g_switchstack_success() noexcept;
// Check the preconditions for switching to this greenlet; if they
// aren't met, throws PyErrOccurred. Most callers will want to
// catch this and clear the arguments
inline void check_switch_allowed() const;
class GreenletStartedWhileInPython : public std::runtime_error
{
public:
GreenletStartedWhileInPython() : std::runtime_error("")
{}
};
protected:
/**
Perform a stack switch into this greenlet.
This temporarily sets the global variable
``switching_thread_state`` to this greenlet; as soon as the
call to ``slp_switch`` completes, this is reset to NULL.
Consequently, this depends on the GIL.
TODO: Adopt the stackman model and pass ``slp_switch`` a
callback function and context pointer; this eliminates the
need for global variables altogether.
Because the stack switch happens in this function, this
function can't use its own stack (local) variables, set
before the switch, and then accessed after the switch.
Further, you con't even access ``g_thread_state_global``
before and after the switch from the global variable.
Because it is thread local some compilers cache it in a
register/on the stack, notably new versions of MSVC; this
breaks with strange crashes sometime later, because writing
to anything in ``g_thread_state_global`` after the switch
is actually writing to random memory. For this reason, we
call a non-inlined function to finish the operation. (XXX:
The ``/GT`` MSVC compiler argument probably fixes that.)
It is very important that stack switch is 'atomic', i.e. no
calls into other Python code allowed (except very few that
are safe), because global variables are very fragile. (This
should no longer be the case with thread-local variables.)
*/
// Made virtual to facilitate subclassing UserGreenlet for testing.
virtual switchstack_result_t g_switchstack(void);
class TracingGuard
{
private:
PyThreadState* tstate;
public:
TracingGuard()
: tstate(PyThreadState_GET())
{
PyThreadState_EnterTracing(this->tstate);
}
~TracingGuard()
{
PyThreadState_LeaveTracing(this->tstate);
this->tstate = nullptr;
}
inline void CallTraceFunction(const OwnedObject& tracefunc,
const greenlet::refs::ImmortalEventName& event,
const BorrowedGreenlet& origin,
const BorrowedGreenlet& target)
{
// TODO: This calls tracefunc(event, (origin, target)). Add a shortcut
// function for that that's specialized to avoid the Py_BuildValue
// string parsing, or start with just using "ON" format with PyTuple_Pack(2,
// origin, target). That seems like what the N format is meant
// for.
// XXX: Why does event not automatically cast back to a PyObject?
// It tries to call the "deleted constructor ImmortalEventName
// const" instead.
assert(tracefunc);
assert(event);
assert(origin);
assert(target);
greenlet::refs::NewReference retval(
PyObject_CallFunction(
tracefunc.borrow(),
"O(OO)",
event.borrow(),
origin.borrow(),
target.borrow()
));
if (!retval) {
throw PyErrOccurred::from_current();
}
}
};
static void
g_calltrace(const OwnedObject& tracefunc,
const greenlet::refs::ImmortalEventName& event,
const greenlet::refs::BorrowedGreenlet& origin,
const BorrowedGreenlet& target);
private:
OwnedObject g_switch_finish(const switchstack_result_t& err);
};
class UserGreenlet : public Greenlet
{
private:
static greenlet::PythonAllocator<UserGreenlet> allocator;
BorrowedGreenlet _self;
OwnedMainGreenlet _main_greenlet;
OwnedObject _run_callable;
OwnedGreenlet _parent;
public:
static void* operator new(size_t UNUSED(count));
static void operator delete(void* ptr);
UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent);
virtual ~UserGreenlet();
virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const;
virtual bool was_running_in_dead_thread() const noexcept;
virtual ThreadState* thread_state() const noexcept;
virtual OwnedObject g_switch();
virtual const OwnedObject& run() const
{
if (this->started() || !this->_run_callable) {
throw AttributeError("run");
}
return this->_run_callable;
}
virtual void run(const refs::BorrowedObject nrun);
virtual const OwnedGreenlet parent() const;
virtual void parent(const refs::BorrowedObject new_parent);
virtual const refs::BorrowedMainGreenlet main_greenlet() const;
virtual BorrowedGreenlet self() const noexcept;
virtual void murder_in_place();
virtual bool belongs_to_thread(const ThreadState* state) const;
virtual int tp_traverse(visitproc visit, void* arg);
virtual int tp_clear();
class ParentIsCurrentGuard
{
private:
OwnedGreenlet oldparent;
UserGreenlet* greenlet;
G_NO_COPIES_OF_CLS(ParentIsCurrentGuard);
public:
ParentIsCurrentGuard(UserGreenlet* p, const ThreadState& thread_state);
~ParentIsCurrentGuard();
};
virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state);
protected:
virtual switchstack_result_t g_initialstub(void* mark);
private:
// This function isn't meant to return.
// This accepts raw pointers and the ownership of them at the
// same time. The caller should use ``inner_bootstrap(origin.relinquish_ownership())``.
void inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run);
};
class BrokenGreenlet : public UserGreenlet
{
private:
static greenlet::PythonAllocator<BrokenGreenlet> allocator;
public:
bool _force_switch_error = false;
bool _force_slp_switch_error = false;
static void* operator new(size_t UNUSED(count));
static void operator delete(void* ptr);
BrokenGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent)
: UserGreenlet(p, the_parent)
{}
virtual ~BrokenGreenlet()
{}
virtual switchstack_result_t g_switchstack(void);
virtual bool force_slp_switch_error() const noexcept;
};
class MainGreenlet : public Greenlet
{
private:
static greenlet::PythonAllocator<MainGreenlet> allocator;
refs::BorrowedMainGreenlet _self;
ThreadState* _thread_state;
G_NO_COPIES_OF_CLS(MainGreenlet);
public:
static void* operator new(size_t UNUSED(count));
static void operator delete(void* ptr);
MainGreenlet(refs::BorrowedMainGreenlet::PyType*, ThreadState*);
virtual ~MainGreenlet();
virtual const OwnedObject& run() const;
virtual void run(const refs::BorrowedObject nrun);
virtual const OwnedGreenlet parent() const;
virtual void parent(const refs::BorrowedObject new_parent);
virtual const refs::BorrowedMainGreenlet main_greenlet() const;
virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const;
virtual bool was_running_in_dead_thread() const noexcept;
virtual ThreadState* thread_state() const noexcept;
void thread_state(ThreadState*) noexcept;
virtual OwnedObject g_switch();
virtual BorrowedGreenlet self() const noexcept;
virtual int tp_traverse(visitproc visit, void* arg);
};
// Instantiate one on the stack to save the GC state,
// and then disable GC. When it goes out of scope, GC will be
// restored to its original state. Sadly, these APIs are only
// available on 3.10+; luckily, we only need them on 3.11+.
#if GREENLET_PY310
class GCDisabledGuard
{
private:
int was_enabled = 0;
public:
GCDisabledGuard()
: was_enabled(PyGC_IsEnabled())
{
PyGC_Disable();
}
~GCDisabledGuard()
{
if (this->was_enabled) {
PyGC_Enable();
}
}
};
#endif
OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept;
//TODO: Greenlet::g_switch() should call this automatically on its
//return value. As it is, the module code is calling it.
static inline OwnedObject
single_result(const OwnedObject& results)
{
if (results
&& PyTuple_Check(results.borrow())
&& PyTuple_GET_SIZE(results.borrow()) == 1) {
PyObject* result = PyTuple_GET_ITEM(results.borrow(), 0);
assert(result);
return OwnedObject::owning(result);
}
return results;
}
static OwnedObject
g_handle_exit(const OwnedObject& greenlet_result);
template<typename T>
void operator<<(const PyThreadState *const lhs, T& rhs)
{
rhs.operator<<(lhs);
}
} // namespace greenlet ;
#endif

View file

@ -1,106 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
#ifndef GREENLET_INTERNAL_H
#define GREENLET_INTERNAL_H
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-function"
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
# pragma clang diagnostic ignored "-Wunused-variable"
#endif
/**
* Implementation helpers.
*
* C++ templates and inline functions should go here.
*/
#define PY_SSIZE_T_CLEAN
#include "greenlet_compiler_compat.hpp"
#include "greenlet_cpython_compat.hpp"
#include "greenlet_exceptions.hpp"
#include "greenlet_greenlet.hpp"
#include "greenlet_allocator.hpp"
#include <vector>
#include <string>
#define GREENLET_MODULE
struct _greenlet;
typedef struct _greenlet PyGreenlet;
namespace greenlet {
class ThreadState;
};
#define implementation_ptr_t greenlet::Greenlet*
#include "greenlet.h"
G_FP_TMPL_STATIC inline void
greenlet::refs::MainGreenletExactChecker(void *p)
{
if (!p) {
return;
}
// We control the class of the main greenlet exactly.
if (Py_TYPE(p) != &PyGreenlet_Type) {
std::string err("MainGreenlet: Expected exactly a greenlet, not a ");
err += Py_TYPE(p)->tp_name;
throw greenlet::TypeError(err);
}
// Greenlets from dead threads no longer respond to main() with a
// true value; so in that case we need to perform an additional
// check.
Greenlet* g = ((PyGreenlet*)p)->pimpl;
if (g->main()) {
return;
}
if (!dynamic_cast<MainGreenlet*>(g)) {
std::string err("MainGreenlet: Expected exactly a main greenlet, not a ");
err += Py_TYPE(p)->tp_name;
throw greenlet::TypeError(err);
}
}
template <typename T, greenlet::refs::TypeChecker TC>
inline greenlet::Greenlet* greenlet::refs::_OwnedGreenlet<T, TC>::operator->() const noexcept
{
return reinterpret_cast<PyGreenlet*>(this->p)->pimpl;
}
template <typename T, greenlet::refs::TypeChecker TC>
inline greenlet::Greenlet* greenlet::refs::_BorrowedGreenlet<T, TC>::operator->() const noexcept
{
return reinterpret_cast<PyGreenlet*>(this->p)->pimpl;
}
#include <memory>
#include <stdexcept>
extern PyTypeObject PyGreenlet_Type;
/**
* Forward declarations needed in multiple files.
*/
static PyGreenlet* green_create_main(greenlet::ThreadState*);
static PyObject* green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs);
static int green_is_gc(BorrowedGreenlet self);
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif
// Local Variables:
// flycheck-clang-include-path: ("../../include" "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/include/python3.10")
// End:

View file

@ -1,99 +0,0 @@
#ifndef GREENLET_SLP_SWITCH_HPP
#define GREENLET_SLP_SWITCH_HPP
#include "greenlet_compiler_compat.hpp"
#include "greenlet_refs.hpp"
/*
* the following macros are spliced into the OS/compiler
* specific code, in order to simplify maintenance.
*/
// We can save about 10% of the time it takes to switch greenlets if
// we thread the thread state through the slp_save_state() and the
// following slp_restore_state() calls from
// slp_switch()->g_switchstack() (which already needs to access it).
//
// However:
//
// that requires changing the prototypes and implementations of the
// switching functions. If we just change the prototype of
// slp_switch() to accept the argument and update the macros, without
// changing the implementation of slp_switch(), we get crashes on
// 64-bit Linux and 32-bit x86 (for reasons that aren't 100% clear);
// on the other hand, 64-bit macOS seems to be fine. Also, 64-bit
// windows is an issue because slp_switch is written fully in assembly
// and currently ignores its argument so some code would have to be
// adjusted there to pass the argument on to the
// ``slp_save_state_asm()`` function (but interestingly, because of
// the calling convention, the extra argument is just ignored and
// things function fine, albeit slower, if we just modify
// ``slp_save_state_asm`()` to fetch the pointer to pass to the
// macro.)
//
// Our compromise is to use a *glabal*, untracked, weak, pointer
// to the necessary thread state during the process of switching only.
// This is safe because we're protected by the GIL, and if we're
// running this code, the thread isn't exiting. This also nets us a
// 10-12% speed improvement.
static greenlet::Greenlet* volatile switching_thread_state = nullptr;
extern "C" {
static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref);
static void GREENLET_NOINLINE(slp_restore_state_trampoline)();
}
#define SLP_SAVE_STATE(stackref, stsizediff) \
do { \
assert(switching_thread_state); \
stackref += STACK_MAGIC; \
if (slp_save_state_trampoline((char*)stackref)) \
return -1; \
if (!switching_thread_state->active()) \
return 1; \
stsizediff = switching_thread_state->stack_start() - (char*)stackref; \
} while (0)
#define SLP_RESTORE_STATE() slp_restore_state_trampoline()
#define SLP_EVAL
extern "C" {
#define slp_switch GREENLET_NOINLINE(slp_switch)
#include "slp_platformselect.h"
}
#undef slp_switch
#ifndef STACK_MAGIC
# error \
"greenlet needs to be ported to this platform, or taught how to detect your compiler properly."
#endif /* !STACK_MAGIC */
#ifdef EXTERNAL_ASM
/* CCP addition: Make these functions, to be called from assembler.
* The token include file for the given platform should enable the
* EXTERNAL_ASM define so that this is included.
*/
extern "C" {
intptr_t
slp_save_state_asm(intptr_t* ref)
{
intptr_t diff;
SLP_SAVE_STATE(ref, diff);
return diff;
}
void
slp_restore_state_asm(void)
{
SLP_RESTORE_STATE();
}
extern int slp_switch(void);
};
#endif
#endif

View file

@ -1,543 +0,0 @@
#ifndef GREENLET_THREAD_STATE_HPP
#define GREENLET_THREAD_STATE_HPP
#include <ctime>
#include <stdexcept>
#include "greenlet_internal.hpp"
#include "greenlet_refs.hpp"
#include "greenlet_thread_support.hpp"
using greenlet::refs::BorrowedObject;
using greenlet::refs::BorrowedGreenlet;
using greenlet::refs::BorrowedMainGreenlet;
using greenlet::refs::OwnedMainGreenlet;
using greenlet::refs::OwnedObject;
using greenlet::refs::OwnedGreenlet;
using greenlet::refs::OwnedList;
using greenlet::refs::PyErrFetchParam;
using greenlet::refs::PyArgParseParam;
using greenlet::refs::ImmortalString;
using greenlet::refs::CreatedModule;
using greenlet::refs::PyErrPieces;
using greenlet::refs::NewReference;
namespace greenlet {
/**
* Thread-local state of greenlets.
*
* Each native thread will get exactly one of these objects,
* automatically accessed through the best available thread-local
* mechanism the compiler supports (``thread_local`` for C++11
* compilers or ``__thread``/``declspec(thread)`` for older GCC/clang
* or MSVC, respectively.)
*
* Previously, we kept thread-local state mostly in a bunch of
* ``static volatile`` variables in the main greenlet file.. This had
* the problem of requiring extra checks, loops, and great care
* accessing these variables if we potentially invoked any Python code
* that could release the GIL, because the state could change out from
* under us. Making the variables thread-local solves this problem.
*
* When we detected that a greenlet API accessing the current greenlet
* was invoked from a different thread than the greenlet belonged to,
* we stored a reference to the greenlet in the Python thread
* dictionary for the thread the greenlet belonged to. This could lead
* to memory leaks if the thread then exited (because of a reference
* cycle, as greenlets referred to the thread dictionary, and deleting
* non-current greenlets leaked their frame plus perhaps arguments on
* the C stack). If a thread exited while still having running
* greenlet objects (perhaps that had just switched back to the main
* greenlet), and did not invoke one of the greenlet APIs *in that
* thread, immediately before it exited, without some other thread
* then being invoked*, such a leak was guaranteed.
*
* This can be partly solved by using compiler thread-local variables
* instead of the Python thread dictionary, thus avoiding a cycle.
*
* To fully solve this problem, we need a reliable way to know that a
* thread is done and we should clean up the main greenlet. On POSIX,
* we can use the destructor function of ``pthread_key_create``, but
* there's nothing similar on Windows; a C++11 thread local object
* reliably invokes its destructor when the thread it belongs to exits
* (non-C++11 compilers offer ``__thread`` or ``declspec(thread)`` to
* create thread-local variables, but they can't hold C++ objects that
* invoke destructors; the C++11 version is the most portable solution
* I found). When the thread exits, we can drop references and
* otherwise manipulate greenlets and frames that we know can no
* longer be switched to. For compilers that don't support C++11
* thread locals, we have a solution that uses the python thread
* dictionary, though it may not collect everything as promptly as
* other compilers do, if some other library is using the thread
* dictionary and has a cycle or extra reference.
*
* There are two small wrinkles. The first is that when the thread
* exits, it is too late to actually invoke Python APIs: the Python
* thread state is gone, and the GIL is released. To solve *this*
* problem, our destructor uses ``Py_AddPendingCall`` to transfer the
* destruction work to the main thread. (This is not an issue for the
* dictionary solution.)
*
* The second is that once the thread exits, the thread local object
* is invalid and we can't even access a pointer to it, so we can't
* pass it to ``Py_AddPendingCall``. This is handled by actually using
* a second object that's thread local (ThreadStateCreator) and having
* it dynamically allocate this object so it can live until the
* pending call runs.
*/
class ThreadState {
private:
// As of commit 08ad1dd7012b101db953f492e0021fb08634afad
// this class needed 56 bytes in o Py_DEBUG build
// on 64-bit macOS 11.
// Adding the vector takes us up to 80 bytes ()
/* Strong reference to the main greenlet */
OwnedMainGreenlet main_greenlet;
/* Strong reference to the current greenlet. */
OwnedGreenlet current_greenlet;
/* Strong reference to the trace function, if any. */
OwnedObject tracefunc;
typedef std::vector<PyGreenlet*, PythonAllocator<PyGreenlet*> > deleteme_t;
/* A vector of raw PyGreenlet pointers representing things that need
deleted when this thread is running. The vector owns the
references, but you need to manually INCREF/DECREF as you use
them. We don't use a vector<refs::OwnedGreenlet> because we
make copy of this vector, and that would become O(n) as all the
refcounts are incremented in the copy.
*/
deleteme_t deleteme;
#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED
void* exception_state;
#endif
static std::clock_t _clocks_used_doing_gc;
static ImmortalString get_referrers_name;
static PythonAllocator<ThreadState> allocator;
G_NO_COPIES_OF_CLS(ThreadState);
public:
static void* operator new(size_t UNUSED(count))
{
return ThreadState::allocator.allocate(1);
}
static void operator delete(void* ptr)
{
return ThreadState::allocator.deallocate(static_cast<ThreadState*>(ptr),
1);
}
static void init()
{
ThreadState::get_referrers_name = "get_referrers";
ThreadState::_clocks_used_doing_gc = 0;
}
ThreadState()
: main_greenlet(OwnedMainGreenlet::consuming(green_create_main(this))),
current_greenlet(main_greenlet)
{
if (!this->main_greenlet) {
// We failed to create the main greenlet. That's bad.
throw PyFatalError("Failed to create main greenlet");
}
// The main greenlet starts with 1 refs: The returned one. We
// then copied it to the current greenlet.
assert(this->main_greenlet.REFCNT() == 2);
#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED
this->exception_state = slp_get_exception_state();
#endif
}
inline void restore_exception_state()
{
#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED
// It's probably important this be inlined and only call C
// functions to avoid adding an SEH frame.
slp_set_exception_state(this->exception_state);
#endif
}
inline bool has_main_greenlet()
{
return !!this->main_greenlet;
}
// Called from the ThreadStateCreator when we're in non-standard
// threading mode. In that case, there is an object in the Python
// thread state dictionary that points to us. The main greenlet
// also traverses into us, in which case it's crucial not to
// traverse back into the main greenlet.
int tp_traverse(visitproc visit, void* arg, bool traverse_main=true)
{
if (traverse_main) {
Py_VISIT(main_greenlet.borrow_o());
}
if (traverse_main || current_greenlet != main_greenlet) {
Py_VISIT(current_greenlet.borrow_o());
}
Py_VISIT(tracefunc.borrow());
return 0;
}
inline BorrowedMainGreenlet borrow_main_greenlet() const
{
assert(this->main_greenlet);
assert(this->main_greenlet.REFCNT() >= 2);
return this->main_greenlet;
};
inline OwnedMainGreenlet get_main_greenlet()
{
return this->main_greenlet;
}
/**
* In addition to returning a new reference to the currunt
* greenlet, this performs any maintenance needed.
*/
inline OwnedGreenlet get_current()
{
/* green_dealloc() cannot delete greenlets from other threads, so
it stores them in the thread dict; delete them now. */
this->clear_deleteme_list();
//assert(this->current_greenlet->main_greenlet == this->main_greenlet);
//assert(this->main_greenlet->main_greenlet == this->main_greenlet);
return this->current_greenlet;
}
/**
* As for non-const get_current();
*/
inline BorrowedGreenlet borrow_current()
{
this->clear_deleteme_list();
return this->current_greenlet;
}
/**
* Does no maintenance.
*/
inline OwnedGreenlet get_current() const
{
return this->current_greenlet;
}
template<typename T, refs::TypeChecker TC>
inline bool is_current(const refs::PyObjectPointer<T, TC>& obj) const
{
return this->current_greenlet.borrow_o() == obj.borrow_o();
}
inline void set_current(const OwnedGreenlet& target)
{
this->current_greenlet = target;
}
private:
/**
* Deref and remove the greenlets from the deleteme list. Must be
* holding the GIL.
*
* If *murder* is true, then we must be called from a different
* thread than the one that these greenlets were running in.
* In that case, if the greenlet was actually running, we destroy
* the frame reference and otherwise make it appear dead before
* proceeding; otherwise, we would try (and fail) to raise an
* exception in it and wind up right back in this list.
*/
inline void clear_deleteme_list(const bool murder=false)
{
if (!this->deleteme.empty()) {
// It's possible we could add items to this list while
// running Python code if there's a thread switch, so we
// need to defensively copy it before that can happen.
deleteme_t copy = this->deleteme;
this->deleteme.clear(); // in case things come back on the list
for(deleteme_t::iterator it = copy.begin(), end = copy.end();
it != end;
++it ) {
PyGreenlet* to_del = *it;
if (murder) {
// Force each greenlet to appear dead; we can't raise an
// exception into it anymore anyway.
to_del->pimpl->murder_in_place();
}
// The only reference to these greenlets should be in
// this list, decreffing them should let them be
// deleted again, triggering calls to green_dealloc()
// in the correct thread (if we're not murdering).
// This may run arbitrary Python code and switch
// threads or greenlets!
Py_DECREF(to_del);
if (PyErr_Occurred()) {
PyErr_WriteUnraisable(nullptr);
PyErr_Clear();
}
}
}
}
public:
/**
* Returns a new reference, or a false object.
*/
inline OwnedObject get_tracefunc() const
{
return tracefunc;
};
inline void set_tracefunc(BorrowedObject tracefunc)
{
assert(tracefunc);
if (tracefunc == BorrowedObject(Py_None)) {
this->tracefunc.CLEAR();
}
else {
this->tracefunc = tracefunc;
}
}
/**
* Given a reference to a greenlet that some other thread
* attempted to delete (has a refcount of 0) store it for later
* deletion when the thread this state belongs to is current.
*/
inline void delete_when_thread_running(PyGreenlet* to_del)
{
Py_INCREF(to_del);
this->deleteme.push_back(to_del);
}
/**
* Set to std::clock_t(-1) to disable.
*/
inline static std::clock_t& clocks_used_doing_gc()
{
return ThreadState::_clocks_used_doing_gc;
}
~ThreadState()
{
if (!PyInterpreterState_Head()) {
// We shouldn't get here (our callers protect us)
// but if we do, all we can do is bail early.
return;
}
// We should not have an "origin" greenlet; that only exists
// for the temporary time during a switch, which should not
// be in progress as the thread dies.
//assert(!this->switching_state.origin);
this->tracefunc.CLEAR();
// Forcibly GC as much as we can.
this->clear_deleteme_list(true);
// The pending call did this.
assert(this->main_greenlet->thread_state() == nullptr);
// If the main greenlet is the current greenlet,
// then we "fell off the end" and the thread died.
// It's possible that there is some other greenlet that
// switched to us, leaving a reference to the main greenlet
// on the stack, somewhere uncollectible. Try to detect that.
if (this->current_greenlet == this->main_greenlet && this->current_greenlet) {
assert(this->current_greenlet->is_currently_running_in_some_thread());
// Drop one reference we hold.
this->current_greenlet.CLEAR();
assert(!this->current_greenlet);
// Only our reference to the main greenlet should be left,
// But hold onto the pointer in case we need to do extra cleanup.
PyGreenlet* old_main_greenlet = this->main_greenlet.borrow();
Py_ssize_t cnt = this->main_greenlet.REFCNT();
this->main_greenlet.CLEAR();
if (ThreadState::_clocks_used_doing_gc != std::clock_t(-1)
&& cnt == 2 && Py_REFCNT(old_main_greenlet) == 1) {
// Highly likely that the reference is somewhere on
// the stack, not reachable by GC. Verify.
// XXX: This is O(n) in the total number of objects.
// TODO: Add a way to disable this at runtime, and
// another way to report on it.
std::clock_t begin = std::clock();
NewReference gc(PyImport_ImportModule("gc"));
if (gc) {
OwnedObject get_referrers = gc.PyRequireAttr(ThreadState::get_referrers_name);
OwnedList refs(get_referrers.PyCall(old_main_greenlet));
if (refs && refs.empty()) {
assert(refs.REFCNT() == 1);
// We found nothing! So we left a dangling
// reference: Probably the last thing some
// other greenlet did was call
// 'getcurrent().parent.switch()' to switch
// back to us. Clean it up. This will be the
// case on CPython 3.7 and newer, as they use
// an internal calling conversion that avoids
// creating method objects and storing them on
// the stack.
Py_DECREF(old_main_greenlet);
}
else if (refs
&& refs.size() == 1
&& PyCFunction_Check(refs.at(0))
&& Py_REFCNT(refs.at(0)) == 2) {
assert(refs.REFCNT() == 1);
// Ok, we found a C method that refers to the
// main greenlet, and its only referenced
// twice, once in the list we just created,
// once from...somewhere else. If we can't
// find where else, then this is a leak.
// This happens in older versions of CPython
// that create a bound method object somewhere
// on the stack that we'll never get back to.
if (PyCFunction_GetFunction(refs.at(0).borrow()) == (PyCFunction)green_switch) {
BorrowedObject function_w = refs.at(0);
refs.clear(); // destroy the reference
// from the list.
// back to one reference. Can *it* be
// found?
assert(function_w.REFCNT() == 1);
refs = get_referrers.PyCall(function_w);
if (refs && refs.empty()) {
// Nope, it can't be found so it won't
// ever be GC'd. Drop it.
Py_CLEAR(function_w);
}
}
}
std::clock_t end = std::clock();
ThreadState::_clocks_used_doing_gc += (end - begin);
}
}
}
// We need to make sure this greenlet appears to be dead,
// because otherwise deallocing it would fail to raise an
// exception in it (the thread is dead) and put it back in our
// deleteme list.
if (this->current_greenlet) {
this->current_greenlet->murder_in_place();
this->current_greenlet.CLEAR();
}
if (this->main_greenlet) {
// Couldn't have been the main greenlet that was running
// when the thread exited (because we already cleared this
// pointer if it was). This shouldn't be possible?
// If the main greenlet was current when the thread died (it
// should be, right?) then we cleared its self pointer above
// when we cleared the current greenlet's main greenlet pointer.
// assert(this->main_greenlet->main_greenlet == this->main_greenlet
// || !this->main_greenlet->main_greenlet);
// // self reference, probably gone
// this->main_greenlet->main_greenlet.CLEAR();
// This will actually go away when the ivar is destructed.
this->main_greenlet.CLEAR();
}
if (PyErr_Occurred()) {
PyErr_WriteUnraisable(NULL);
PyErr_Clear();
}
}
};
ImmortalString ThreadState::get_referrers_name(nullptr);
PythonAllocator<ThreadState> ThreadState::allocator;
std::clock_t ThreadState::_clocks_used_doing_gc(0);
template<typename Destructor>
class ThreadStateCreator
{
private:
// Initialized to 1, and, if still 1, created on access.
// Set to 0 on destruction.
ThreadState* _state;
G_NO_COPIES_OF_CLS(ThreadStateCreator);
public:
// Only one of these, auto created per thread
ThreadStateCreator() :
_state((ThreadState*)1)
{
}
~ThreadStateCreator()
{
ThreadState* tmp = this->_state;
this->_state = nullptr;
if (tmp && tmp != (ThreadState*)1) {
Destructor x(tmp);
}
}
inline ThreadState& state()
{
// The main greenlet will own this pointer when it is created,
// which will be right after this. The plan is to give every
// greenlet a pointer to the main greenlet for the thread it
// runs in; if we are doing something cross-thread, we need to
// access the pointer from the main greenlet. Deleting the
// thread, and hence the thread-local storage, will delete the
// state pointer in the main greenlet.
if (this->_state == (ThreadState*)1) {
// XXX: Assuming allocation never fails
this->_state = new ThreadState;
// For non-standard threading, we need to store an object
// in the Python thread state dictionary so that it can be
// DECREF'd when the thread ends (ideally; the dict could
// last longer) and clean this object up.
}
if (!this->_state) {
throw std::runtime_error("Accessing state after destruction.");
}
return *this->_state;
}
operator ThreadState&()
{
return this->state();
}
operator ThreadState*()
{
return &this->state();
}
inline int tp_traverse(visitproc visit, void* arg)
{
if (this->_state) {
return this->_state->tp_traverse(visit, arg);
}
return 0;
}
};
// We can't use the PythonAllocator for this, because we push to it
// from the thread state destructor, which doesn't have the GIL,
// and Python's allocators can only be called with the GIL.
typedef std::vector<ThreadState*> cleanup_queue_t;
}; // namespace greenlet
#endif

View file

@ -1,118 +0,0 @@
#ifndef GREENLET_THREAD_STATE_DICT_CLEANUP_HPP
#define GREENLET_THREAD_STATE_DICT_CLEANUP_HPP
#include "greenlet_internal.hpp"
#include "greenlet_thread_state.hpp"
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
#endif
#ifndef G_THREAD_STATE_DICT_CLEANUP_TYPE
// shut the compiler up if it looks at this file in isolation
#define ThreadStateCreator int
#endif
// Define a Python object that goes in the Python thread state dict
// when the greenlet thread state is created, and which owns the
// reference to the greenlet thread local state.
// When the thread state dict is cleaned up, so too is the thread
// state. This works best if we make sure there are no circular
// references to the thread state.
typedef struct _PyGreenletCleanup {
PyObject_HEAD
ThreadStateCreator* thread_state_creator;
} PyGreenletCleanup;
static void
cleanup_do_dealloc(PyGreenletCleanup* self)
{
ThreadStateCreator* tmp = self->thread_state_creator;
self->thread_state_creator = nullptr;
if (tmp) {
delete tmp;
}
}
static void
cleanup_dealloc(PyGreenletCleanup* self)
{
PyObject_GC_UnTrack(self);
cleanup_do_dealloc(self);
}
static int
cleanup_clear(PyGreenletCleanup* self)
{
// This method is never called by our test cases.
cleanup_do_dealloc(self);
return 0;
}
static int
cleanup_traverse(PyGreenletCleanup* self, visitproc visit, void* arg)
{
if (self->thread_state_creator) {
return self->thread_state_creator->tp_traverse(visit, arg);
}
return 0;
}
static int
cleanup_is_gc(PyGreenlet* UNUSED(self))
{
return 1;
}
static PyTypeObject PyGreenletCleanup_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"greenlet._greenlet.ThreadStateCleanup",
sizeof(struct _PyGreenletCleanup),
0, /* tp_itemsize */
/* methods */
(destructor)cleanup_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as _number*/
0, /* tp_as _sequence*/
0, /* tp_as _mapping*/
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer*/
G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
"Internal use only", /* tp_doc */
(traverseproc)cleanup_traverse, /* tp_traverse */
(inquiry)cleanup_clear, /* tp_clear */
0, /* tp_richcompare */
// XXX: Don't our flags promise a weakref?
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
PyType_GenericNew, /* tp_new */
PyObject_GC_Del, /* tp_free */
(inquiry)cleanup_is_gc, /* tp_is_gc */
};
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#endif

View file

@ -1,31 +0,0 @@
#ifndef GREENLET_THREAD_SUPPORT_HPP
#define GREENLET_THREAD_SUPPORT_HPP
/**
* Defines various utility functions to help greenlet integrate well
* with threads. This used to be needed when we supported Python
* 2.7 on Windows, which used a very old compiler. We wrote an
* alternative implementation using Python APIs and POSIX or Windows
* APIs, but that's no longer needed. So this file is a shadow of its
* former self --- but may be needed in the future.
*/
#include <stdexcept>
#include <thread>
#include <mutex>
#include "greenlet_compiler_compat.hpp"
namespace greenlet {
typedef std::mutex Mutex;
typedef std::lock_guard<Mutex> LockGuard;
class LockInitError : public std::runtime_error
{
public:
LockInitError(const char* what) : std::runtime_error(what)
{};
};
};
#endif /* GREENLET_THREAD_SUPPORT_HPP */

View file

@ -1,2 +0,0 @@
call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64
ml64 /nologo /c /Fo switch_x64_masm.obj switch_x64_masm.asm

View file

@ -1,124 +0,0 @@
/*
* this is the internal transfer function.
*
* HISTORY
* 07-Sep-16 Add clang support using x register naming. Fredrik Fornwall
* 13-Apr-13 Add support for strange GCC caller-save decisions
* 08-Apr-13 File creation. Michael Matz
*
* NOTES
*
* Simply save all callee saved registers
*
*/
#define STACK_REFPLUS 1
#ifdef SLP_EVAL
#define STACK_MAGIC 0
#define REGS_TO_SAVE "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", \
"x27", "x28", "x30" /* aka lr */, \
"v8", "v9", "v10", "v11", \
"v12", "v13", "v14", "v15"
/*
* Recall:
asm asm-qualifiers ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
or (if asm-qualifiers contains 'goto')
asm asm-qualifiers ( AssemblerTemplate
: OutputOperands
: InputOperands
: Clobbers
: GotoLabels)
and OutputOperands are
[ [asmSymbolicName] ] constraint (cvariablename)
When a name is given, refer to it as ``%[the name]``.
When not given, ``%i`` where ``i`` is the zero-based index.
constraints starting with ``=`` means only writing; ``+`` means
reading and writing.
This is followed by ``r`` (must be register) or ``m`` (must be memory)
and these can be combined.
The ``cvariablename`` is actually an lvalue expression.
In AArch65, 31 general purpose registers. If named X0... they are
64-bit. If named W0... they are the bottom 32 bits of the
corresponding 64 bit register.
XZR and WZR are hardcoded to 0, and ignore writes.
Arguments are in X0..X7. C++ uses X0 for ``this``. X0 holds simple return
values (?)
Whenever a W register is written, the top half of the X register is zeroed.
*/
static int
slp_switch(void)
{
int err;
void *fp;
/* Windowz uses a 32-bit long on a 64-bit platform, unlike the rest of
the world, and in theory we can be compiled with GCC/llvm on 64-bit
windows. So we need a fixed-width type.
*/
int64_t *stackref, stsizediff;
__asm__ volatile ("" : : : REGS_TO_SAVE);
__asm__ volatile ("str x29, %0" : "=m"(fp) : : );
__asm__ ("mov %0, sp" : "=r" (stackref));
{
SLP_SAVE_STATE(stackref, stsizediff);
__asm__ volatile (
"add sp,sp,%0\n"
"add x29,x29,%0\n"
:
: "r" (stsizediff)
);
SLP_RESTORE_STATE();
/* SLP_SAVE_STATE macro contains some return statements
(of -1 and 1). It falls through only when
the return value of slp_save_state() is zero, which
is placed in x0.
In that case we (slp_switch) also want to return zero
(also in x0 of course).
Now, some GCC versions (seen with 4.8) think it's a
good idea to save/restore x0 around the call to
slp_restore_state(), instead of simply zeroing it
at the return below. But slp_restore_state
writes random values to the stack slot used for this
save/restore (from when it once was saved above in
SLP_SAVE_STATE, when it was still uninitialized), so
"restoring" that precious zero actually makes us
return random values. There are some ways to make
GCC not use that zero value in the normal return path
(e.g. making err volatile, but that costs a little
stack space), and the simplest is to call a function
that returns an unknown value (which happens to be zero),
so the saved/restored value is unused.
Thus, this line stores a 0 into the ``err`` variable
(which must be held in a register for this instruction,
of course). The ``w`` qualifier causes the instruction
to use W0 instead of X0, otherwise we get a warning
about a value size mismatch (because err is an int,
and aarch64 platforms are LP64: 32-bit int, 64 bit long
and pointer).
*/
__asm__ volatile ("mov %w0, #0" : "=r" (err));
}
__asm__ volatile ("ldr x29, %0" : : "m" (fp) :);
__asm__ volatile ("" : : : REGS_TO_SAVE);
return err;
}
#endif

View file

@ -1,30 +0,0 @@
#define STACK_REFPLUS 1
#ifdef SLP_EVAL
#define STACK_MAGIC 0
#define REGS_TO_SAVE "$9", "$10", "$11", "$12", "$13", "$14", "$15", \
"$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9"
static int
slp_switch(void)
{
int ret;
long *stackref, stsizediff;
__asm__ volatile ("" : : : REGS_TO_SAVE);
__asm__ volatile ("mov $30, %0" : "=r" (stackref) : );
{
SLP_SAVE_STATE(stackref, stsizediff);
__asm__ volatile (
"addq $30, %0, $30\n\t"
: /* no outputs */
: "r" (stsizediff)
);
SLP_RESTORE_STATE();
}
__asm__ volatile ("" : : : REGS_TO_SAVE);
__asm__ volatile ("mov $31, %0" : "=r" (ret) : );
return ret;
}
#endif

View file

@ -1,87 +0,0 @@
/*
* this is the internal transfer function.
*
* HISTORY
* 3-May-13 Ralf Schmitt <ralf@systemexit.de>
* Add support for strange GCC caller-save decisions
* (ported from switch_aarch64_gcc.h)
* 18-Aug-11 Alexey Borzenkov <snaury@gmail.com>
* Correctly save rbp, csr and cw
* 01-Apr-04 Hye-Shik Chang <perky@FreeBSD.org>
* Ported from i386 to amd64.
* 24-Nov-02 Christian Tismer <tismer@tismer.com>
* needed to add another magic constant to insure
* that f in slp_eval_frame(PyFrameObject *f)
* STACK_REFPLUS will probably be 1 in most cases.
* gets included into the saved stack area.
* 17-Sep-02 Christian Tismer <tismer@tismer.com>
* after virtualizing stack save/restore, the
* stack size shrunk a bit. Needed to introduce
* an adjustment STACK_MAGIC per platform.
* 15-Sep-02 Gerd Woetzel <gerd.woetzel@GMD.DE>
* slightly changed framework for spark
* 31-Avr-02 Armin Rigo <arigo@ulb.ac.be>
* Added ebx, esi and edi register-saves.
* 01-Mar-02 Samual M. Rushing <rushing@ironport.com>
* Ported from i386.
*/
#define STACK_REFPLUS 1
#ifdef SLP_EVAL
/* #define STACK_MAGIC 3 */
/* the above works fine with gcc 2.96, but 2.95.3 wants this */
#define STACK_MAGIC 0
#define REGS_TO_SAVE "r12", "r13", "r14", "r15"
static int
slp_switch(void)
{
int err;
void* rbp;
void* rbx;
unsigned int csr;
unsigned short cw;
/* This used to be declared 'register', but that does nothing in
modern compilers and is explicitly forbidden in some new
standards. */
long *stackref, stsizediff;
__asm__ volatile ("" : : : REGS_TO_SAVE);
__asm__ volatile ("fstcw %0" : "=m" (cw));
__asm__ volatile ("stmxcsr %0" : "=m" (csr));
__asm__ volatile ("movq %%rbp, %0" : "=m" (rbp));
__asm__ volatile ("movq %%rbx, %0" : "=m" (rbx));
__asm__ ("movq %%rsp, %0" : "=g" (stackref));
{
SLP_SAVE_STATE(stackref, stsizediff);
__asm__ volatile (
"addq %0, %%rsp\n"
"addq %0, %%rbp\n"
:
: "r" (stsizediff)
);
SLP_RESTORE_STATE();
__asm__ volatile ("xorq %%rax, %%rax" : "=a" (err));
}
__asm__ volatile ("movq %0, %%rbx" : : "m" (rbx));
__asm__ volatile ("movq %0, %%rbp" : : "m" (rbp));
__asm__ volatile ("ldmxcsr %0" : : "m" (csr));
__asm__ volatile ("fldcw %0" : : "m" (cw));
__asm__ volatile ("" : : : REGS_TO_SAVE);
return err;
}
#endif
/*
* further self-processing support
*/
/*
* if you want to add self-inspection tools, place them
* here. See the x86_msvc for the necessary defines.
* These features are highly experimental und not
* essential yet.
*/

View file

@ -1,79 +0,0 @@
/*
* this is the internal transfer function.
*
* HISTORY
* 14-Aug-06 File creation. Ported from Arm Thumb. Sylvain Baro
* 3-Sep-06 Commented out saving of r1-r3 (r4 already commented out) as I
* read that these do not need to be saved. Also added notes and
* errors related to the frame pointer. Richard Tew.
*
* NOTES
*
* It is not possible to detect if fp is used or not, so the supplied
* switch function needs to support it, so that you can remove it if
* it does not apply to you.
*
* POSSIBLE ERRORS
*
* "fp cannot be used in asm here"
*
* - Try commenting out "fp" in REGS_TO_SAVE.
*
*/
#define STACK_REFPLUS 1
#ifdef SLP_EVAL
#define STACK_MAGIC 0
#define REG_SP "sp"
#define REG_SPSP "sp,sp"
#ifdef __thumb__
#define REG_FP "r7"
#define REG_FPFP "r7,r7"
#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r9", "r10", "r11", "lr"
#else
#define REG_FP "fp"
#define REG_FPFP "fp,fp"
#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r8", "r9", "r10", "lr"
#endif
#if defined(__SOFTFP__)
#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL
#elif defined(__VFP_FP__)
#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \
"d12", "d13", "d14", "d15"
#elif defined(__MAVERICK__)
#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "mvf4", "mvf5", "mvf6", "mvf7", \
"mvf8", "mvf9", "mvf10", "mvf11", \
"mvf12", "mvf13", "mvf14", "mvf15"
#else
#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "f4", "f5", "f6", "f7"
#endif
static int
#ifdef __GNUC__
__attribute__((optimize("no-omit-frame-pointer")))
#endif
slp_switch(void)
{
void *fp;
int *stackref, stsizediff;
int result;
__asm__ volatile ("" : : : REGS_TO_SAVE);
__asm__ volatile ("mov r0," REG_FP "\n\tstr r0,%0" : "=m" (fp) : : "r0");
__asm__ ("mov %0," REG_SP : "=r" (stackref));
{
SLP_SAVE_STATE(stackref, stsizediff);
__asm__ volatile (
"add " REG_SPSP ",%0\n"
"add " REG_FPFP ",%0\n"
:
: "r" (stsizediff)
);
SLP_RESTORE_STATE();
}
__asm__ volatile ("ldr r0,%1\n\tmov " REG_FP ",r0\n\tmov %0, #0" : "=r" (result) : "m" (fp) : "r0");
__asm__ volatile ("" : : : REGS_TO_SAVE);
return result;
}
#endif

View file

@ -1,67 +0,0 @@
/*
* this is the internal transfer function.
*
* HISTORY
* 31-May-15 iOS support. Ported from arm32. Proton <feisuzhu@163.com>
*
* NOTES
*
* It is not possible to detect if fp is used or not, so the supplied
* switch function needs to support it, so that you can remove it if
* it does not apply to you.
*
* POSSIBLE ERRORS
*
* "fp cannot be used in asm here"
*
* - Try commenting out "fp" in REGS_TO_SAVE.
*
*/
#define STACK_REFPLUS 1
#ifdef SLP_EVAL
#define STACK_MAGIC 0
#define REG_SP "sp"
#define REG_SPSP "sp,sp"
#define REG_FP "r7"
#define REG_FPFP "r7,r7"
#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r10", "r11", "lr"
#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \
"d12", "d13", "d14", "d15"
static int
#ifdef __GNUC__
__attribute__((optimize("no-omit-frame-pointer")))
#endif
slp_switch(void)
{
void *fp;
int *stackref, stsizediff, result;
__asm__ volatile ("" : : : REGS_TO_SAVE);
__asm__ volatile ("str " REG_FP ",%0" : "=m" (fp));
__asm__ ("mov %0," REG_SP : "=r" (stackref));
{
SLP_SAVE_STATE(stackref, stsizediff);
__asm__ volatile (
"add " REG_SPSP ",%0\n"
"add " REG_FPFP ",%0\n"
:
: "r" (stsizediff)
: REGS_TO_SAVE /* Clobber registers, force compiler to
* recalculate address of void *fp from REG_SP or REG_FP */
);
SLP_RESTORE_STATE();
}
__asm__ volatile (
"ldr " REG_FP ", %1\n\t"
"mov %0, #0"
: "=r" (result)
: "m" (fp)
: REGS_TO_SAVE /* Force compiler to restore saved registers after this */
);
return result;
}
#endif

View file

@ -1,53 +0,0 @@
AREA switch_arm64_masm, CODE, READONLY;
GLOBAL slp_switch [FUNC]
EXTERN slp_save_state_asm
EXTERN slp_restore_state_asm
slp_switch
; push callee saved registers to stack
stp x19, x20, [sp, #-16]!
stp x21, x22, [sp, #-16]!
stp x23, x24, [sp, #-16]!
stp x25, x26, [sp, #-16]!
stp x27, x28, [sp, #-16]!
stp x29, x30, [sp, #-16]!
stp d8, d9, [sp, #-16]!
stp d10, d11, [sp, #-16]!
stp d12, d13, [sp, #-16]!
stp d14, d15, [sp, #-16]!
; call slp_save_state_asm with stack pointer
mov x0, sp
bl slp_save_state_asm
; early return for return value of 1 and -1
cmp x0, #-1
b.eq RETURN
cmp x0, #1
b.eq RETURN
; increment stack and frame pointer
add sp, sp, x0
add x29, x29, x0
bl slp_restore_state_asm
; store return value for successful completion of routine
mov x0, #0
RETURN
; pop registers from stack
ldp d14, d15, [sp], #16
ldp d12, d13, [sp], #16
ldp d10, d11, [sp], #16
ldp d8, d9, [sp], #16
ldp x29, x30, [sp], #16
ldp x27, x28, [sp], #16
ldp x25, x26, [sp], #16
ldp x23, x24, [sp], #16
ldp x21, x22, [sp], #16
ldp x19, x20, [sp], #16
ret
END

Some files were not shown because too many files have changed in this diff Show more