diff --git a/BackEndChallenge/.vscode/settings.json b/BackEndChallenge/.vscode/settings.json new file mode 100644 index 000000000..0abf078c7 --- /dev/null +++ b/BackEndChallenge/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python" +} \ No newline at end of file diff --git a/BackEndChallenge/README.md b/BackEndChallenge/README.md new file mode 100644 index 000000000..dd7f07876 --- /dev/null +++ b/BackEndChallenge/README.md @@ -0,0 +1,69 @@ + + +
+

+ +

Headstorm Engineering Back End Challenge

+ +

+ I made a rest API using flask for the /data entry point. +

+

+ + + + +
+

Table of Contents

+
    +
  1. Built With
  2. +
  3. + Run the project +
  4. +
  5. Improvements
  6. +
  7. Contact
  8. +
+
+ + + + +### Built With + +* []() Python +* []() HTML + +### Using + +* []() Flask, python microframework +* []() Flask's SQLAlchemy & Flask's Restful API + + + +## Getting Started + +To get a local copy up and running follow these simple steps. + +### Prerequisites + +You will need to have python 3.8.5 & flask installed along with the flask dependencies that are listed at the top of the app.py file. Specifically install flask_sqlalchemy & flask_restful along with flask. + +### Installation + +1. Clone my repo :) +2. Install flask & flask requirements +3. I set up a virtual environment & installed flask & the dependencies that way +4. To run my virtual environment, type "source bin/activate" from the myproject directory + +### Run The Project +4. Type "python app.py" + +### Improvements +* I did not get a chance to add the requirements about the input being 500 numbers as json input. My current program takes in 5 numbers. It checks that there are exactly 5 integers, but does not check that there are 500 or the input. It only works if there are 5 numbers separated by commas. This addition to meet the 500 json requirements could be +* met with more time. + +### Contact +Please contact me with any issues running the code: +* email: emm190@pitt.edu +* phone: 330-987-0225 +* linkedIn: https://www.linkedin.com/in/emilymiller21/ diff --git a/BackEndChallenge/myproject/app.py b/BackEndChallenge/myproject/app.py new file mode 100644 index 000000000..cda4074d8 --- /dev/null +++ b/BackEndChallenge/myproject/app.py @@ -0,0 +1,95 @@ +from flask import Flask +from flask_restful import Resource, Api +from flask import render_template +from flask import request +from flask import jsonify +from flask import redirect +from flask import url_for +from flask_sqlalchemy import SQLAlchemy +import re +from flask import flash + + +app = Flask(__name__) +api = Api(app) +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' +db = SQLAlchemy(app) + + +class Number(db.Model): + id = db.Column(db.Integer, primary_key=True) + numbers = db.Column(db.String(80), unique=False, nullable=False) + + def __repr__(self): + return '%s' % ( + self.numbers) + + def __init__(self, numbers): + self.numbers = numbers + +db.create_all() + +@app.route('/') +def home_page(): + example_embed='Hello! Welcome to my submission for the backend challenge.' + return render_template('index.html', embed=example_embed) + +@app.route('/data',methods = ['POST', 'GET']) +def data(): + if request.method == 'POST': + numbers = request.form['numbers'] + stringList = numbers + number1 = Number(stringList) + db.session.add(number1) + db.session.commit() + idNumber = number1.id + listOfNumbers = str(stringList) + user = listOfNumbers.split(',') + for x in user: + try: + int(x) + except: + error_msg='There is something wrong with your formatting. Make sure you did not enter any letters. The only acceptable input is numbers separated by commas (with no space at the end)' + return render_template('index.html', embed=error_msg) + intList = [int(x) for x in user] + print(intList) + if (len(intList)!=5): + error_msg='You have to enter 5 numbers. You did not. Try again' + return render_template('index.html', embed=error_msg) + print(idNumber) + return redirect(url_for('success',listOfNumbers = Number.query.filter_by(id=idNumber).all())) + else: + user = request.args.get('numbers') + lastQuery = Number.query.count() + print(Number.query.all()) + return redirect(url_for('success',listOfNumbers = Number.query.filter_by(id=lastQuery).all())) + +@app.route('/getValue',methods = ['POST']) +def getValue(): + numbers = request.form['numbersOfRequest'] + return redirect(url_for('success',listOfNumbers = Number.query.filter_by(id=numbers).all())) + +@app.route('/success/') +def success(listOfNumbers): + listOfNumbers = str(listOfNumbers) + user = listOfNumbers.split(',') + print(user) + intList = [int(x) for x in user] + intList.sort() + print(intList) + return 'This is your sorted list of numbers:%s' % str(intList) + +@app.route('/showAll', methods = ['POST', 'GET']) +def showAll(): + print(Number.query.count()) + list = [] + for x in range(Number.query.count()): + print(Number.query.filter_by(id=x).all()) + list.append("%d:" %x) + list.append(Number.query.filter_by(id=x).all()) + listOfNumbers = Number.query.all() + print(listOfNumbers) + return 'This is all of the submissions:%s' % list + +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file diff --git a/BackEndChallenge/myproject/bin/Activate.ps1 b/BackEndChallenge/myproject/bin/Activate.ps1 new file mode 100644 index 000000000..2fb3852c3 --- /dev/null +++ b/BackEndChallenge/myproject/bin/Activate.ps1 @@ -0,0 +1,241 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/BackEndChallenge/myproject/bin/activate b/BackEndChallenge/myproject/bin/activate new file mode 100644 index 000000000..6e615a2f6 --- /dev/null +++ b/BackEndChallenge/myproject/bin/activate @@ -0,0 +1,76 @@ +# 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 + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/Users/emilymariemiller/Desktop/FrontEndChallenge/BackEndChallenge/myproject" +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:-}" + if [ "x(myproject) " != x ] ; then + PS1="(myproject) ${PS1:-}" + else + if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" + fi + fi + export PS1 +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r +fi diff --git a/BackEndChallenge/myproject/bin/activate.csh b/BackEndChallenge/myproject/bin/activate.csh new file mode 100644 index 000000000..65a0cbc18 --- /dev/null +++ b/BackEndChallenge/myproject/bin/activate.csh @@ -0,0 +1,37 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/Users/emilymariemiller/Desktop/FrontEndChallenge/BackEndChallenge/myproject" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + if ("myproject" != "") then + set env_name = "myproject" + else + if (`basename "VIRTUAL_ENV"` == "__") then + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` + else + set env_name = `basename "$VIRTUAL_ENV"` + endif + endif + set prompt = "[$env_name] $prompt" + unset env_name +endif + +alias pydoc python -m pydoc + +rehash diff --git a/BackEndChallenge/myproject/bin/activate.fish b/BackEndChallenge/myproject/bin/activate.fish new file mode 100644 index 000000000..bf30a8abb --- /dev/null +++ b/BackEndChallenge/myproject/bin/activate.fish @@ -0,0 +1,75 @@ +# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org) +# you cannot run it directly + +function deactivate -d "Exit virtualenv and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + functions -e fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + + set -e VIRTUAL_ENV + if test "$argv[1]" != "nondestructive" + # Self destruct! + functions -e deactivate + end +end + +# unset irrelevant variables +deactivate nondestructive + +set -gx VIRTUAL_ENV "/Users/emilymariemiller/Desktop/FrontEndChallenge/BackEndChallenge/myproject" + +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 + + # Prompt override? + if test -n "(myproject) " + printf "%s%s" "(myproject) " (set_color normal) + else + # ...Otherwise, prepend env + set -l _checkbase (basename "$VIRTUAL_ENV") + if test $_checkbase = "__" + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) + else + printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) + end + end + + # Restore the return status of the previous command. + echo "exit $old_status" | . + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/BackEndChallenge/myproject/bin/easy_install b/BackEndChallenge/myproject/bin/easy_install new file mode 100755 index 000000000..e5e690f28 --- /dev/null +++ b/BackEndChallenge/myproject/bin/easy_install @@ -0,0 +1,8 @@ +#!/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/BackEndChallenge/myproject/bin/easy_install-3.8 b/BackEndChallenge/myproject/bin/easy_install-3.8 new file mode 100755 index 000000000..e5e690f28 --- /dev/null +++ b/BackEndChallenge/myproject/bin/easy_install-3.8 @@ -0,0 +1,8 @@ +#!/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/BackEndChallenge/myproject/bin/flask b/BackEndChallenge/myproject/bin/flask new file mode 100755 index 000000000..9d50d5314 --- /dev/null +++ b/BackEndChallenge/myproject/bin/flask @@ -0,0 +1,8 @@ +#!/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from flask.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/BackEndChallenge/myproject/bin/normalizer b/BackEndChallenge/myproject/bin/normalizer new file mode 100755 index 000000000..d190d0e16 --- /dev/null +++ b/BackEndChallenge/myproject/bin/normalizer @@ -0,0 +1,8 @@ +#!/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from charset_normalizer.cli.normalizer import cli_detect +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(cli_detect()) diff --git a/BackEndChallenge/myproject/bin/pip b/BackEndChallenge/myproject/bin/pip new file mode 100755 index 000000000..e8cb11e15 --- /dev/null +++ b/BackEndChallenge/myproject/bin/pip @@ -0,0 +1,8 @@ +#!/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/BackEndChallenge/myproject/bin/pip3 b/BackEndChallenge/myproject/bin/pip3 new file mode 100755 index 000000000..e8cb11e15 --- /dev/null +++ b/BackEndChallenge/myproject/bin/pip3 @@ -0,0 +1,8 @@ +#!/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/BackEndChallenge/myproject/bin/pip3.8 b/BackEndChallenge/myproject/bin/pip3.8 new file mode 100755 index 000000000..e8cb11e15 --- /dev/null +++ b/BackEndChallenge/myproject/bin/pip3.8 @@ -0,0 +1,8 @@ +#!/Users/emilymariemiller/Desktop/BackEndChallenge/myproject/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/BackEndChallenge/myproject/bin/python b/BackEndChallenge/myproject/bin/python new file mode 120000 index 000000000..b8a0adbbb --- /dev/null +++ b/BackEndChallenge/myproject/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/BackEndChallenge/myproject/bin/python3 b/BackEndChallenge/myproject/bin/python3 new file mode 120000 index 000000000..79ab74b1e --- /dev/null +++ b/BackEndChallenge/myproject/bin/python3 @@ -0,0 +1 @@ +/usr/local/bin/python3 \ No newline at end of file diff --git a/BackEndChallenge/myproject/include/site/python3.8/greenlet/greenlet.h b/BackEndChallenge/myproject/include/site/python3.8/greenlet/greenlet.h new file mode 100644 index 000000000..830bef8dd --- /dev/null +++ b/BackEndChallenge/myproject/include/site/python3.8/greenlet/greenlet.h @@ -0,0 +1,146 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ + +/* Greenlet object interface */ + +#ifndef Py_GREENLETOBJECT_H +#define Py_GREENLETOBJECT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is deprecated and undocumented. It does not change. */ +#define GREENLET_VERSION "1.0.0" + +typedef struct _greenlet { + PyObject_HEAD + char* stack_start; + char* stack_stop; + char* stack_copy; + intptr_t stack_saved; + struct _greenlet* stack_prev; + struct _greenlet* parent; + PyObject* run_info; + struct _frame* top_frame; + int recursion_depth; + PyObject* weakreflist; +#if PY_VERSION_HEX >= 0x030700A3 + _PyErr_StackItem* exc_info; + _PyErr_StackItem exc_state; +#else + PyObject* exc_type; + PyObject* exc_value; + PyObject* exc_traceback; +#endif + PyObject* dict; +#if PY_VERSION_HEX >= 0x030700A3 + PyObject* context; +#endif +#if PY_VERSION_HEX >= 0x30A00B1 + CFrame* cframe; +#endif +} PyGreenlet; + +#define PyGreenlet_Check(op) PyObject_TypeCheck(op, &PyGreenlet_Type) +#define PyGreenlet_MAIN(op) (((PyGreenlet*)(op))->stack_stop == (char*)-1) +#define PyGreenlet_STARTED(op) (((PyGreenlet*)(op))->stack_stop != NULL) +#define PyGreenlet_ACTIVE(op) (((PyGreenlet*)(op))->stack_start != NULL) +#define PyGreenlet_GET_PARENT(op) (((PyGreenlet*)(op))->parent) + +/* C API functions */ + +/* Total number of symbols that are exported */ +#define PyGreenlet_API_pointers 8 + +#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 + +#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]) + +/* 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 */ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/LICENSE.rst b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/LICENSE.rst new file mode 100644 index 000000000..9d227a0cc --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/METADATA new file mode 100644 index 000000000..2b881c2b6 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/METADATA @@ -0,0 +1,124 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 2.0.1 +Summary: A simple framework for building complex web applications. +Home-page: https://palletsprojects.com/p/flask +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://flask.palletsprojects.com/ +Project-URL: Changes, https://flask.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/flask/ +Project-URL: Issue Tracker, https://github.com/pallets/flask/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +Requires-Dist: Werkzeug (>=2.0) +Requires-Dist: Jinja2 (>=3.0) +Requires-Dist: itsdangerous (>=2.0) +Requires-Dist: click (>=7.1.2) +Provides-Extra: async +Requires-Dist: asgiref (>=3.2) ; extra == 'async' +Provides-Extra: dotenv +Requires-Dist: python-dotenv ; extra == 'dotenv' + +Flask +===== + +Flask is a lightweight `WSGI`_ web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around `Werkzeug`_ +and `Jinja`_ and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + +.. _WSGI: https://wsgi.readthedocs.io/ +.. _Werkzeug: https://werkzeug.palletsprojects.com/ +.. _Jinja: https://jinja.palletsprojects.com/ + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Flask + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +A Simple Example +---------------- + +.. code-block:: python + + # save this as app.py + from flask import Flask + + app = Flask(__name__) + + @app.route("/") + def hello(): + return "Hello, World!" + +.. code-block:: text + + $ flask run + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) + + +Contributing +------------ + +For guidance on setting up a development environment and how to make a +contribution to Flask, see the `contributing guidelines`_. + +.. _contributing guidelines: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst + + +Donate +------ + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://flask.palletsprojects.com/ +- Changes: https://flask.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Flask/ +- Source Code: https://github.com/pallets/flask/ +- Issue Tracker: https://github.com/pallets/flask/issues/ +- Website: https://palletsprojects.com/p/flask/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/RECORD new file mode 100644 index 000000000..3bffacb02 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/RECORD @@ -0,0 +1,51 @@ +../../../bin/flask,sha256=GulQcAKkwivvfvdavQo-FLnItaZsoVT8rsIA6kg-d-8,262 +Flask-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask-2.0.1.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +Flask-2.0.1.dist-info/METADATA,sha256=50Jm1647RKw98p4RF64bCqRh0wajk-n3hQ7av2-pniA,3808 +Flask-2.0.1.dist-info/RECORD,, +Flask-2.0.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +Flask-2.0.1.dist-info/entry_points.txt,sha256=gBLA1aKg0OYR8AhbAfg8lnburHtKcgJLDU52BBctN0k,42 +Flask-2.0.1.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 +flask/__init__.py,sha256=w5v6GCNm8eLDMNWqs2ue7HLHo75aslAwz1h3k3YO9HY,2251 +flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 +flask/__pycache__/__init__.cpython-38.pyc,, +flask/__pycache__/__main__.cpython-38.pyc,, +flask/__pycache__/app.cpython-38.pyc,, +flask/__pycache__/blueprints.cpython-38.pyc,, +flask/__pycache__/cli.cpython-38.pyc,, +flask/__pycache__/config.cpython-38.pyc,, +flask/__pycache__/ctx.cpython-38.pyc,, +flask/__pycache__/debughelpers.cpython-38.pyc,, +flask/__pycache__/globals.cpython-38.pyc,, +flask/__pycache__/helpers.cpython-38.pyc,, +flask/__pycache__/logging.cpython-38.pyc,, +flask/__pycache__/scaffold.cpython-38.pyc,, +flask/__pycache__/sessions.cpython-38.pyc,, +flask/__pycache__/signals.cpython-38.pyc,, +flask/__pycache__/templating.cpython-38.pyc,, +flask/__pycache__/testing.cpython-38.pyc,, +flask/__pycache__/typing.cpython-38.pyc,, +flask/__pycache__/views.cpython-38.pyc,, +flask/__pycache__/wrappers.cpython-38.pyc,, +flask/app.py,sha256=q6lpiiWVxjljQRwjjneUBpfllXYPEq0CFAUpTQ5gIeA,82376 +flask/blueprints.py,sha256=OjI-dkwx96ZNMUGDDFMKzgcpUJf240WRuMlHkmgI1Lc,23541 +flask/cli.py,sha256=iN1pL2SevE5Nmvey-0WwnxG3nipZXIiE__Ed4lx3IuM,32036 +flask/config.py,sha256=jj_7JGen_kYuTlKrx8ZPBsZddb8mihC0ODg4gcjXBX8,11068 +flask/ctx.py,sha256=EM3W0v1ctuFQAGk_HWtQdoJEg_r2f5Le4xcmElxFwwk,17428 +flask/debughelpers.py,sha256=wk5HtLwENsQ4e8tkxfBn6ykUeVRDuMbQCKgtEVe6jxk,6171 +flask/globals.py,sha256=cWd-R2hUH3VqPhnmQNww892tQS6Yjqg_wg8UvW1M7NM,1723 +flask/helpers.py,sha256=00WqA3wYeyjMrnAOPZTUyrnUf7H8ik3CVT0kqGl_qjk,30589 +flask/json/__init__.py,sha256=d-db2DJMASq0G7CI-JvobehRE1asNRGX1rIDQ1GF9WM,11580 +flask/json/__pycache__/__init__.cpython-38.pyc,, +flask/json/__pycache__/tag.cpython-38.pyc,, +flask/json/tag.py,sha256=fys3HBLssWHuMAIJuTcf2K0bCtosePBKXIWASZEEjnU,8857 +flask/logging.py,sha256=1o_hirVGqdj7SBdETnhX7IAjklG89RXlrwz_2CjzQQE,2273 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/scaffold.py,sha256=EhQuiFrdcmJHxqPGQkEpqLsEUZ7ULZD0rtED2NrduvM,32400 +flask/sessions.py,sha256=Kb7zY4qBIOU2cw1xM5mQ_KmgYUBDFbUYWjlkq0EFYis,15189 +flask/signals.py,sha256=HQWgBEXlrLbHwLBoWqAStJKcN-rsB1_AMO8-VZ7LDOo,2126 +flask/templating.py,sha256=l96VD39JQ0nue4Bcj7wZ4-FWWs-ppLxvgBCpwDQ4KAk,5626 +flask/testing.py,sha256=OsHT-2B70abWH3ulY9IbhLchXIeyj3L-cfcDa88wv5E,10281 +flask/typing.py,sha256=zVqhz53KklncAv-WxbpxGZfaRGOqeWAsLdP1tTMaCuE,1684 +flask/views.py,sha256=F2PpWPloe4x0906IUjnPcsOqg5YvmQIfk07_lFeAD4s,5865 +flask/wrappers.py,sha256=VndbHPRBSUUOejmd2Y3ydkoCVUtsS2OJIdJEVIkBVD8,5604 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/WHEEL new file mode 100644 index 000000000..385faab05 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/entry_points.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/entry_points.txt new file mode 100644 index 000000000..1eb025200 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask = flask.cli:main + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/top_level.txt new file mode 100644 index 000000000..7e1060246 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask-2.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/AUTHORS.md b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/AUTHORS.md new file mode 100644 index 000000000..bbcfb5c55 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/AUTHORS.md @@ -0,0 +1,132 @@ +Authors +======= + +A huge thanks to all of our contributors: + +- Adam Chainz +- Alec Nikolas Reiter +- Alex Gaynor +- Alex M +- Alex Morken +- Andrew Dunham +- Andriy Yurchuk +- Anil Kulkarni +- Antonio Dourado +- Antonio Herraiz +- Ares Ou +- Artur Rodrigues +- Axel Haustant +- Belousow Makc +- Benjamin Dopplinger +- Bennett, Bryan +- Bohan Zhang +- Bryan Bennett +- Bulat Bochkariov +- Cameron Brandon White +- Catherine Devlin +- Dan Quirk +- Daniele Esposti +- Dario Bertini +- David Arnold +- David Baumgold +- David Boucha +- David Crawford +- Dimitris Theodorou +- Doug Black +- Evan Dale Aromin +- Eyal Levin +- Francesco Della Vedova +- Frank Stratton +- Garret Raziel +- Gary Belvin +- Gilles Dartiguelongue +- Giorgio Salluzzo +- Guillaume BINET +- Heston Liebowitz +- Hu WQ +- Jacob Magnusson +- James Booth +- James Ogura +- James Turk +- Jeff Widman +- Joakim Ekberg +- Johannes +- Jordan Yelloz +- Josh Friend +- Joshua C. Randall +- Joshua Randall +- José Fernández Ramos +- Juan Rossi +- JuneHyeon Bae +- Kamil Gałuszka +- Kevin Burke +- Kevin Deldycke +- Kevin Funk +- Kyle Conroy +- Lance Ingle +- Lars Holm Nielsen +- Luiz Armesto +- Malthe Borch +- Marek Hlobil +- Matt Wright +- Max Mautner +- Max Peterson +- Maxim +- Michael Hwang +- Michael Newman +- Miguel Grinberg +- Mihai Tomescu +- Neil Halelamien +- Nicolas Harraudeau +- Pavel Tyslyatsky +- Petrus J.v.Rensburg +- Philippe Ndiaye +- Piotr Husiatyński +- Prasanna Swaminathan +- Robert Warner +- Rod Cloutier +- Ryan Horn +- Rémi Alvergnat +- Sam Kimbrel +- Samarth Shah +- Sami Jaktholm +- Sander Sink +- Sasha Baranov +- Saul Diez-Guerra +- Sergey Romanov +- Shreyans Sheth +- Steven Leggett +- Sven-Hendrik Haase +- Usman Ehtesham Gul +- Victor Neo +- Vlad Frolov +- Vladimir Pal +- WooParadog +- Yaniv Aknin +- akash +- bret barker +- hachichaud +- jbouzekri +- jobou +- johnrichter +- justanr +- k-funk +- kelvinhammond +- kenjones +- kieran gorman +- kumy +- lyschoening +- mailto1587 +- mniebla +- mozillazg +- muchosalsa +- nachinius +- nixdata +- papaeye +- pingz +- saml +- siavashg +- silasray +- soasme +- ueg1990 +- y-p diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/LICENSE b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/LICENSE new file mode 100644 index 000000000..3337f9081 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2013, Twilio, Inc. +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 Twilio, Inc. nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/METADATA new file mode 100644 index 000000000..7a675ffc4 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/METADATA @@ -0,0 +1,29 @@ +Metadata-Version: 2.1 +Name: Flask-RESTful +Version: 0.3.9 +Summary: Simple framework for creating REST APIs +Home-page: https://www.github.com/flask-restful/flask-restful/ +Author: Twilio API Team +Author-email: help@twilio.com +License: BSD +Platform: any +Classifier: Framework :: Flask +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: License :: OSI Approved :: BSD License +Requires-Dist: aniso8601 (>=0.82) +Requires-Dist: Flask (>=0.8) +Requires-Dist: six (>=1.3.0) +Requires-Dist: pytz +Provides-Extra: docs +Requires-Dist: sphinx ; extra == 'docs' + +UNKNOWN + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/RECORD new file mode 100644 index 000000000..b450f72e9 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/RECORD @@ -0,0 +1,27 @@ +Flask_RESTful-0.3.9.dist-info/AUTHORS.md,sha256=HBq00z_VgMI2xfwfUobrU16_qamdouMkpNxbR0BzaVg,1992 +Flask_RESTful-0.3.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask_RESTful-0.3.9.dist-info/LICENSE,sha256=PFjoO0Jk5okmshAgMix5-RZTC0sFT_EJWpC_CtQcCyM,1485 +Flask_RESTful-0.3.9.dist-info/METADATA,sha256=yWXNzKn9mvIHmJcxWZoBd6VQ85cEr8rST1jQqH19J0k,912 +Flask_RESTful-0.3.9.dist-info/RECORD,, +Flask_RESTful-0.3.9.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +Flask_RESTful-0.3.9.dist-info/top_level.txt,sha256=lNpWPlejgBAtMhCUwz_FTyJH12ul1mBZ-Uv3ZK1HiGg,14 +flask_restful/__init__.py,sha256=_QIzQv1R0fjbHhDflmchzRt7FxCTd859RyzynnemUSc,27859 +flask_restful/__pycache__/__init__.cpython-38.pyc,, +flask_restful/__pycache__/__version__.cpython-38.pyc,, +flask_restful/__pycache__/fields.cpython-38.pyc,, +flask_restful/__pycache__/inputs.cpython-38.pyc,, +flask_restful/__pycache__/reqparse.cpython-38.pyc,, +flask_restful/__version__.py,sha256=Cl8F3ydkBARpLLyugWqxgTxF5alkKcuTblk74Tuiw0I,45 +flask_restful/fields.py,sha256=43GbFejZ3kiOb20A1QuzLXjevfsxMZSbmpOpGtW56vo,13018 +flask_restful/inputs.py,sha256=561w8fjLqBq4I_7yXPHJM567ijWhpuf8d8uZnKzTehA,9118 +flask_restful/representations/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +flask_restful/representations/__pycache__/__init__.cpython-38.pyc,, +flask_restful/representations/__pycache__/json.cpython-38.pyc,, +flask_restful/representations/json.py,sha256=swKwnbt7v2ioHfHkqhqbzIu_yrcP0ComlSl49IGFJOo,873 +flask_restful/reqparse.py,sha256=-xZmkyrvDFfGvFFokTtXe4J-2PWnNX4EfKolhkT995E,14681 +flask_restful/utils/__init__.py,sha256=jgedvOLGeTk4Sqox4WHE_vAFLP0T_PrLHO4PXaqFqxw,723 +flask_restful/utils/__pycache__/__init__.cpython-38.pyc,, +flask_restful/utils/__pycache__/cors.cpython-38.pyc,, +flask_restful/utils/__pycache__/crypto.cpython-38.pyc,, +flask_restful/utils/cors.py,sha256=cZiqaHhIn0w66spRoSIdC-jIn4X_b6OlVms5eGF4Ess,2084 +flask_restful/utils/crypto.py,sha256=q3PBvAYMJYybbqqQlKNF_Pqeyo9h3x5jFJuVqtEA5bA,996 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/WHEEL new file mode 100644 index 000000000..01b8fc7d4 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/top_level.txt new file mode 100644 index 000000000..f7b852702 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_RESTful-0.3.9.dist-info/top_level.txt @@ -0,0 +1 @@ +flask_restful diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/LICENSE.rst b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/LICENSE.rst new file mode 100644 index 000000000..9d227a0cc --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/METADATA new file mode 100644 index 000000000..a1971dc2d --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/METADATA @@ -0,0 +1,94 @@ +Metadata-Version: 2.1 +Name: Flask-SQLAlchemy +Version: 2.5.1 +Summary: Adds SQLAlchemy support to your Flask application. +Home-page: https://github.com/pallets/flask-sqlalchemy +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://flask-sqlalchemy.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/flask-sqlalchemy +Project-URL: Issue tracker, https://github.com/pallets/flask-sqlalchemy/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.* +Requires-Dist: Flask (>=0.10) +Requires-Dist: SQLAlchemy (>=0.8.0) + +Flask-SQLAlchemy +================ + +Flask-SQLAlchemy is an extension for `Flask`_ that adds support for +`SQLAlchemy`_ to your application. It aims to simplify using SQLAlchemy +with Flask by providing useful defaults and extra helpers that make it +easier to accomplish common tasks. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Flask-SQLAlchemy + + +A Simple Example +---------------- + +.. code-block:: python + + from flask import Flask + from flask_sqlalchemy import SQLAlchemy + + app = Flask(__name__) + app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///example.sqlite" + db = SQLAlchemy(app) + + + class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String, unique=True, nullable=False) + email = db.Column(db.String, unique=True, nullable=False) + + + db.session.add(User(name="Flask", email="example@example.com")) + db.session.commit() + + users = User.query.all() + + +Links +----- + +- Documentation: https://flask-sqlalchemy.palletsprojects.com/ +- Releases: https://pypi.org/project/Flask-SQLAlchemy/ +- Code: https://github.com/pallets/flask-sqlalchemy +- Issue tracker: https://github.com/pallets/flask-sqlalchemy/issues +- Test status: https://travis-ci.org/pallets/flask-sqlalchemy +- Test coverage: https://codecov.io/gh/pallets/flask-sqlalchemy + +.. _Flask: https://palletsprojects.com/p/flask/ +.. _SQLAlchemy: https://www.sqlalchemy.org +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/RECORD new file mode 100644 index 000000000..69abba111 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/RECORD @@ -0,0 +1,14 @@ +Flask_SQLAlchemy-2.5.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask_SQLAlchemy-2.5.1.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +Flask_SQLAlchemy-2.5.1.dist-info/METADATA,sha256=vVCeMtTM_xOrUVoVyemeNaTUI5L9iXa16NsiMDDOgFU,3128 +Flask_SQLAlchemy-2.5.1.dist-info/RECORD,, +Flask_SQLAlchemy-2.5.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +Flask_SQLAlchemy-2.5.1.dist-info/top_level.txt,sha256=w2K4fNNoTh4HItoFfz2FRQShSeLcvHYrzU_sZov21QU,17 +flask_sqlalchemy/__init__.py,sha256=IaupgTRkQnY05KPLYvfiNnJdrmwoyfsxaiyGtrEYfO4,40738 +flask_sqlalchemy/__pycache__/__init__.cpython-38.pyc,, +flask_sqlalchemy/__pycache__/_compat.cpython-38.pyc,, +flask_sqlalchemy/__pycache__/model.cpython-38.pyc,, +flask_sqlalchemy/__pycache__/utils.cpython-38.pyc,, +flask_sqlalchemy/_compat.py,sha256=yua0ZSgVWwi56QpEgwaPInzkNQ9PFb7YQdvEk3dImXo,821 +flask_sqlalchemy/model.py,sha256=bd2mIv9LA1A2MZkQObgnMUCSrxNvyqplaSkCxyxKNxY,4988 +flask_sqlalchemy/utils.py,sha256=4eHqAbYElnJ3NbSAHhuINckoAHDABoxjleMJD0iKgyg,1390 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/WHEEL new file mode 100644 index 000000000..01b8fc7d4 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/top_level.txt new file mode 100644 index 000000000..8a5538e94 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Flask_SQLAlchemy-2.5.1.dist-info/top_level.txt @@ -0,0 +1 @@ +flask_sqlalchemy diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/LICENSE.rst b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/LICENSE.rst new file mode 100644 index 000000000..c37cae49e --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/METADATA new file mode 100644 index 000000000..afd84cb77 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/METADATA @@ -0,0 +1,112 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.0.1 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/jinja/ +Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +Requires-Dist: MarkupSafe (>=2.0) +Provides-Extra: i18n +Requires-Dist: Babel (>=2.7) ; extra == 'i18n' + +Jinja +===== + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Jinja2 + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +In A Nutshell +------------- + +.. code-block:: jinja + + {% extends "base.html" %} + {% block title %}Members{% endblock %} + {% block content %} + + {% endblock %} + + +Donate +------ + +The Pallets organization develops and supports Jinja and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://jinja.palletsprojects.com/ +- Changes: https://jinja.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Jinja2/ +- Source Code: https://github.com/pallets/jinja/ +- Issue Tracker: https://github.com/pallets/jinja/issues/ +- Website: https://palletsprojects.com/p/jinja/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/RECORD new file mode 100644 index 000000000..b4692b446 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/RECORD @@ -0,0 +1,58 @@ +Jinja2-3.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-3.0.1.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-3.0.1.dist-info/METADATA,sha256=k6STiOONbGESP2rEKmjhznuG10vm9sNCHCUQL9AQFM4,3508 +Jinja2-3.0.1.dist-info/RECORD,, +Jinja2-3.0.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +Jinja2-3.0.1.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61 +Jinja2-3.0.1.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=fd8jaCRsCATgC7ahuUTD8CyfQoc4aRfALEIny4mwfog,2205 +jinja2/__pycache__/__init__.cpython-38.pyc,, +jinja2/__pycache__/_identifier.cpython-38.pyc,, +jinja2/__pycache__/async_utils.cpython-38.pyc,, +jinja2/__pycache__/bccache.cpython-38.pyc,, +jinja2/__pycache__/compiler.cpython-38.pyc,, +jinja2/__pycache__/constants.cpython-38.pyc,, +jinja2/__pycache__/debug.cpython-38.pyc,, +jinja2/__pycache__/defaults.cpython-38.pyc,, +jinja2/__pycache__/environment.cpython-38.pyc,, +jinja2/__pycache__/exceptions.cpython-38.pyc,, +jinja2/__pycache__/ext.cpython-38.pyc,, +jinja2/__pycache__/filters.cpython-38.pyc,, +jinja2/__pycache__/idtracking.cpython-38.pyc,, +jinja2/__pycache__/lexer.cpython-38.pyc,, +jinja2/__pycache__/loaders.cpython-38.pyc,, +jinja2/__pycache__/meta.cpython-38.pyc,, +jinja2/__pycache__/nativetypes.cpython-38.pyc,, +jinja2/__pycache__/nodes.cpython-38.pyc,, +jinja2/__pycache__/optimizer.cpython-38.pyc,, +jinja2/__pycache__/parser.cpython-38.pyc,, +jinja2/__pycache__/runtime.cpython-38.pyc,, +jinja2/__pycache__/sandbox.cpython-38.pyc,, +jinja2/__pycache__/tests.cpython-38.pyc,, +jinja2/__pycache__/utils.cpython-38.pyc,, +jinja2/__pycache__/visitor.cpython-38.pyc,, +jinja2/_identifier.py,sha256=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775 +jinja2/async_utils.py,sha256=bY2nCUfBA_4FSnNUsIsJgljBq3hACr6fzLi7LiyMTn8,1751 +jinja2/bccache.py,sha256=smAvSDgDSvXdvJzCN_9s0XfkVpQEu8be-QwgeMlrwiM,12677 +jinja2/compiler.py,sha256=qq0Fo9EpDAEwHPLAs3sAP7dindUvDrFrbx4AcB8xV5M,72046 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=uBmrsiwjYH5l14R9STn5mydOOyriBYol5lDGvEqAb3A,9238 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=T6U4be9mY1CUXXin_EQFwpvpFqCiryweGqzXGRYIoSA,61573 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=44SjDjeYkkxQTpmC2BetOTxEFMgQ42p2dfSwXmPFcSo,32122 +jinja2/filters.py,sha256=LslRsJd0JVFBHtdfU_WraM1eQitotciwawiW-seR42U,52577 +jinja2/idtracking.py,sha256=KdFVohVNK-baOwt_INPMco19D7AfLDEN8i3_JoiYnGQ,10713 +jinja2/lexer.py,sha256=D5qOKB3KnRqK9gPAZFQvRguomYsQok5-14TKiWTN8Jw,29923 +jinja2/loaders.py,sha256=ePpWB0xDrILgLVqNFcxqqSbPizsI0T-JlkNEUFqq9fo,22350 +jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396 +jinja2/nativetypes.py,sha256=62hvvsAxAj0YaxylOHoREYVogJ5JqOlJISgGY3OKd_o,3675 +jinja2/nodes.py,sha256=LHF97fu6GW4r2Z9UaOX92MOT1wZpdS9Nx4N-5Fp5ti8,34509 +jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650 +jinja2/parser.py,sha256=kHnU8v92GwMYkfr0MVakWv8UlSf_kJPx8LUsgQMof70,39767 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=bSWdawLjReKpKHhF3-96OIuWYpUy1yxFJCN3jBYyoXc,35013 +jinja2/sandbox.py,sha256=-8zxR6TO9kUkciAVFsIKu8Oq-C7PTeYEdZ5TtA55-gw,14600 +jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905 +jinja2/utils.py,sha256=0wGkxDbxlW10y0ac4-kEiy1Bn0AsWXqz8uomK9Ugy1Q,26961 +jinja2/visitor.py,sha256=ZmeLuTj66ic35-uFH-1m0EKXiw4ObDDb_WuE6h5vPFg,3572 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/WHEEL new file mode 100644 index 000000000..385faab05 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/entry_points.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/entry_points.txt new file mode 100644 index 000000000..3619483fd --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract [i18n] + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/top_level.txt new file mode 100644 index 000000000..7f7afbf3b --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Jinja2-3.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/LICENSE.rst b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/LICENSE.rst new file mode 100644 index 000000000..9d227a0cc --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/METADATA new file mode 100644 index 000000000..ef44e2b35 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/METADATA @@ -0,0 +1,100 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.0.1 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/markupsafe/ +Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst + +MarkupSafe +========== + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +Examples +-------- + +.. code-block:: pycon + + >>> from markupsafe import Markup, escape + + >>> # escape replaces special characters and wraps in Markup + >>> escape("") + Markup('<script>alert(document.cookie);</script>') + + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup("Hello") + Markup('hello') + + >>> escape(Markup("Hello")) + Markup('hello') + + >>> # Markup is a str subclass + >>> # methods and operators escape their arguments + >>> template = Markup("Hello {name}") + >>> template.format(name='"World"') + Markup('Hello "World"') + + +Donate +------ + +The Pallets organization develops and supports MarkupSafe and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://markupsafe.palletsprojects.com/ +- Changes: https://markupsafe.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/MarkupSafe/ +- Source Code: https://github.com/pallets/markupsafe/ +- Issue Tracker: https://github.com/pallets/markupsafe/issues/ +- Website: https://palletsprojects.com/p/markupsafe/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/RECORD new file mode 100644 index 000000000..274f15114 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-2.0.1.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-2.0.1.dist-info/METADATA,sha256=FmPpxBdaqCCjF-XKqoxeEzqAzhetQnrkkSsd3V3X-Jc,3211 +MarkupSafe-2.0.1.dist-info/RECORD,, +MarkupSafe-2.0.1.dist-info/WHEEL,sha256=RA4ju32EWHpO-G1BhxTQ3AwXQWjnnrzYGkM9skoN7_I,109 +MarkupSafe-2.0.1.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=9Tez4UIlI7J6_sQcUFK1dKniT_b_8YefpGIyYJ3Sr2Q,8923 +markupsafe/__pycache__/__init__.cpython-38.pyc,, +markupsafe/__pycache__/_native.cpython-38.pyc,, +markupsafe/_native.py,sha256=GTKEV-bWgZuSjklhMHOYRHU9k0DMewTf5mVEZfkbuns,1986 +markupsafe/_speedups.c,sha256=CDDtwaV21D2nYtypnMQzxvvpZpcTvIs8OZ6KDa1g4t0,7400 +markupsafe/_speedups.cpython-38-darwin.so,sha256=Tjek-7TDXevv7qgNBsLLUfsOQlfCSCGzhhV5cCUrIxk,35480 +markupsafe/_speedups.pyi,sha256=vfMCsOgbAXRNLUXkyuyonG8uEWKYU4PDqNuMaDELAYw,229 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/WHEEL new file mode 100644 index 000000000..d70ba8e3f --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: false +Tag: cp38-cp38-macosx_10_9_x86_64 + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/top_level.txt new file mode 100644 index 000000000..75bf72925 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/MarkupSafe-2.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/AUTHORS.rst b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/AUTHORS.rst new file mode 100644 index 000000000..88e2b6ad7 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/AUTHORS.rst @@ -0,0 +1,7 @@ +Authors +======= + +``pyjwt`` is currently written and maintained by `Jose Padilla `_. +Originally written and maintained by `Jeff Lindsay `_. + +A full list of contributors can be found on GitHub’s `overview `_. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/LICENSE b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/LICENSE new file mode 100644 index 000000000..bdc7819ea --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 José Padilla + +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. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/METADATA new file mode 100644 index 000000000..bcffde027 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/METADATA @@ -0,0 +1,107 @@ +Metadata-Version: 2.1 +Name: PyJWT +Version: 2.1.0 +Summary: JSON Web Token implementation in Python +Home-page: https://github.com/jpadilla/pyjwt +Author: Jose Padilla +Author-email: hello@jpadilla.com +License: MIT +Keywords: json,jwt,security,signing,token,web +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +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: Topic :: Utilities +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +Provides-Extra: crypto +Requires-Dist: cryptography (<4.0.0,>=3.3.1) ; extra == 'crypto' +Provides-Extra: dev +Requires-Dist: sphinx ; extra == 'dev' +Requires-Dist: sphinx-rtd-theme ; extra == 'dev' +Requires-Dist: zope.interface ; extra == 'dev' +Requires-Dist: cryptography (<4.0.0,>=3.3.1) ; extra == 'dev' +Requires-Dist: pytest (<7.0.0,>=6.0.0) ; extra == 'dev' +Requires-Dist: coverage[toml] (==5.0.4) ; extra == 'dev' +Requires-Dist: mypy ; extra == 'dev' +Requires-Dist: pre-commit ; extra == 'dev' +Provides-Extra: docs +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: sphinx-rtd-theme ; extra == 'docs' +Requires-Dist: zope.interface ; extra == 'docs' +Provides-Extra: tests +Requires-Dist: pytest (<7.0.0,>=6.0.0) ; extra == 'tests' +Requires-Dist: coverage[toml] (==5.0.4) ; extra == 'tests' + +PyJWT +===== + +.. image:: https://github.com/jpadilla/pyjwt/workflows/CI/badge.svg + :target: https://github.com/jpadilla/pyjwt/actions?query=workflow%3ACI + +.. image:: https://img.shields.io/pypi/v/pyjwt.svg + :target: https://pypi.python.org/pypi/pyjwt + +.. image:: https://codecov.io/gh/jpadilla/pyjwt/branch/master/graph/badge.svg + :target: https://codecov.io/gh/jpadilla/pyjwt + +.. image:: https://readthedocs.org/projects/pyjwt/badge/?version=stable + :target: https://pyjwt.readthedocs.io/en/stable/ + +A Python implementation of `RFC 7519 `_. Original implementation was written by `@progrium `_. + +Sponsor +------- + ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| |auth0-logo| | If you want to quickly add secure token-based authentication to Python projects, feel free to check Auth0's Python SDK and free plan at `auth0.com/developers `_. | ++--------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +.. |auth0-logo| image:: https://user-images.githubusercontent.com/83319/31722733-de95bbde-b3ea-11e7-96bf-4f4e8f915588.png + +Installing +---------- + +Install with **pip**: + +.. code-block:: console + + $ pip install PyJWT + + +Usage +----- + +.. code-block:: pycon + + >>> import jwt + >>> encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256") + >>> print(encoded) + eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb21lIjoicGF5bG9hZCJ9.Joh1R2dYzkRvDkqv3sygm5YyK8Gi4ShZqbhK2gxcs2U + >>> jwt.decode(encoded, "secret", algorithms=["HS256"]) + {'some': 'payload'} + +Documentation +------------- + +View the full docs online at https://pyjwt.readthedocs.io/en/stable/ + + +Tests +----- + +You can run tests from the project root after cloning with: + +.. code-block:: console + + $ tox + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/RECORD new file mode 100644 index 000000000..d3672d9bf --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/RECORD @@ -0,0 +1,26 @@ +PyJWT-2.1.0.dist-info/AUTHORS.rst,sha256=klzkNGECnu2_VY7At89_xLBF3vUSDruXk3xwgUBxzwc,322 +PyJWT-2.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +PyJWT-2.1.0.dist-info/LICENSE,sha256=7IKvgVtfnahoWvswDMW-t5SeHCK3m2wcBUeWzv32ysY,1080 +PyJWT-2.1.0.dist-info/METADATA,sha256=2vRT2aeTtvTv0o7j4HHrHbURKRmBKcqK67MzbohMzTU,4038 +PyJWT-2.1.0.dist-info/RECORD,, +PyJWT-2.1.0.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92 +PyJWT-2.1.0.dist-info/top_level.txt,sha256=RP5DHNyJbMq2ka0FmfTgoSaQzh7e3r5XuCWCO8a00k8,4 +jwt/__init__.py,sha256=sFr_nBprCwgyk8IerQErQTon5AIG2_gRQZp0QycEArQ,1554 +jwt/__pycache__/__init__.cpython-38.pyc,, +jwt/__pycache__/algorithms.cpython-38.pyc,, +jwt/__pycache__/api_jwk.cpython-38.pyc,, +jwt/__pycache__/api_jws.cpython-38.pyc,, +jwt/__pycache__/api_jwt.cpython-38.pyc,, +jwt/__pycache__/exceptions.cpython-38.pyc,, +jwt/__pycache__/help.cpython-38.pyc,, +jwt/__pycache__/jwks_client.cpython-38.pyc,, +jwt/__pycache__/utils.cpython-38.pyc,, +jwt/algorithms.py,sha256=PUu9HVet1dp2T19Gr-jTnxXhbpqLg8cptdKx8wPUzkk,21471 +jwt/api_jwk.py,sha256=JBdmXMshAonpN5-yzaf0P3d8fElW9jj-eCLE1TjDX-Q,2942 +jwt/api_jws.py,sha256=XoTnwXbGjwGY1wQIa1AQczQ0hZ3YeIozlyQkcZfNJpM,7838 +jwt/api_jwt.py,sha256=YcIM3puo4dsobUfNY1yh6geji_MQTDp79IFWz7cRboY,7306 +jwt/exceptions.py,sha256=MOFQCg96ZiX1VqjBtysg1VAANcSTZ_XVSLSaHiHgP-I,965 +jwt/help.py,sha256=KwGMUMWdSt_AN9PoJhE0JmwpPzTqvlYauhdktXpcbcE,1608 +jwt/jwks_client.py,sha256=NlSWvhl3Dx3nlS_8WuyikUCy9CLAREghFpmXrdKjN6M,1927 +jwt/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jwt/utils.py,sha256=Mjmmb8jZxuFpf77aQF4n4fU-RoQEz2eIPm1RJG0RkOU,2510 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/WHEEL new file mode 100644 index 000000000..83ff02e96 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/top_level.txt new file mode 100644 index 000000000..27ccc9bc3 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/PyJWT-2.1.0.dist-info/top_level.txt @@ -0,0 +1 @@ +jwt diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/LICENSE b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/LICENSE new file mode 100644 index 000000000..0d9fb6dc4 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright 2005-2021 SQLAlchemy authors 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. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/METADATA new file mode 100644 index 000000000..690c11705 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/METADATA @@ -0,0 +1,238 @@ +Metadata-Version: 2.1 +Name: SQLAlchemy +Version: 1.4.25 +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/ +Platform: UNKNOWN +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 :: 2 +Classifier: Programming Language :: Python :: 2.7 +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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Database :: Front-Ends +Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7 +Description-Content-Type: text/x-rst +Requires-Dist: importlib-metadata ; python_version < "3.8" +Requires-Dist: greenlet (!=0.4.17) ; python_version >= "3" and (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")))))) +Provides-Extra: aiomysql +Requires-Dist: greenlet (!=0.4.17) ; (python_version >= "3") and extra == 'aiomysql' +Requires-Dist: aiomysql ; (python_version >= "3") and extra == 'aiomysql' +Provides-Extra: aiosqlite +Requires-Dist: typing-extensions (!=3.10.0.1) ; extra == 'aiosqlite' +Requires-Dist: greenlet (!=0.4.17) ; (python_version >= "3") and extra == 'aiosqlite' +Requires-Dist: aiosqlite ; (python_version >= "3") and extra == 'aiosqlite' +Provides-Extra: asyncio +Requires-Dist: greenlet (!=0.4.17) ; (python_version >= "3") and extra == 'asyncio' +Provides-Extra: asyncmy +Requires-Dist: greenlet (!=0.4.17) ; (python_version >= "3") and extra == 'asyncmy' +Requires-Dist: asyncmy (>=0.2.0) ; (python_version >= "3") and extra == 'asyncmy' +Provides-Extra: mariadb_connector +Requires-Dist: mariadb (>=1.0.1) ; (python_version >= "3") and 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: sqlalchemy2-stubs ; extra == 'mypy' +Requires-Dist: mypy (>=0.910) ; (python_version >= "3") and extra == 'mypy' +Provides-Extra: mysql +Requires-Dist: mysqlclient (<2,>=1.4.0) ; (python_version < "3") and extra == 'mysql' +Requires-Dist: mysqlclient (>=1.4.0) ; (python_version >= "3") and extra == 'mysql' +Provides-Extra: mysql_connector +Requires-Dist: mysql-connector-python ; extra == 'mysql_connector' +Provides-Extra: oracle +Requires-Dist: cx-oracle (<8,>=7) ; (python_version < "3") and extra == 'oracle' +Requires-Dist: cx-oracle (>=7) ; (python_version >= "3") and extra == 'oracle' +Provides-Extra: postgresql +Requires-Dist: psycopg2 (>=2.7) ; extra == 'postgresql' +Provides-Extra: postgresql_asyncpg +Requires-Dist: greenlet (!=0.4.17) ; (python_version >= "3") and extra == 'postgresql_asyncpg' +Requires-Dist: asyncpg ; (python_version >= "3") and extra == 'postgresql_asyncpg' +Provides-Extra: postgresql_pg8000 +Requires-Dist: pg8000 (>=1.16.6) ; extra == 'postgresql_pg8000' +Provides-Extra: postgresql_psycopg2binary +Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary' +Provides-Extra: postgresql_psycopg2cffi +Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi' +Provides-Extra: pymysql +Requires-Dist: pymysql (<1) ; (python_version < "3") and extra == 'pymysql' +Requires-Dist: pymysql ; (python_version >= "3") and extra == 'pymysql' +Provides-Extra: sqlcipher +Requires-Dist: sqlcipher3-binary ; (python_version >= "3") and 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://img.shields.io/pypi/dm/sqlalchemy + :target: https://pypi.org/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 `_. + +Getting Help / Development / Bug reporting +------------------------------------------ + +Please refer to the `SQLAlchemy Community Guide `_. + +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 `_. + +License +------- + +SQLAlchemy is distributed under the `MIT license +`_. + + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/RECORD new file mode 100644 index 000000000..3648ff611 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/RECORD @@ -0,0 +1,481 @@ +SQLAlchemy-1.4.25.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +SQLAlchemy-1.4.25.dist-info/LICENSE,sha256=_-DCK5JvsC0ovMsgocueJWTu1m_PSeTv7r8oHE-pf6c,1100 +SQLAlchemy-1.4.25.dist-info/METADATA,sha256=tbsTIUy2y_AH1pdfS1jtggdJMJOJA8rCUeFTCpmUD4Q,9894 +SQLAlchemy-1.4.25.dist-info/RECORD,, +SQLAlchemy-1.4.25.dist-info/WHEEL,sha256=Hxr7O-X8T9h9kBRUEXrRY-j217oAickuD6_DXvSLvAU,110 +SQLAlchemy-1.4.25.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11 +sqlalchemy/__init__.py,sha256=DnLaRhiKd-Ob5GVsFZr9N9Fvk3TyQD5HVg0zJNno9bo,4085 +sqlalchemy/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/__pycache__/events.cpython-38.pyc,, +sqlalchemy/__pycache__/exc.cpython-38.pyc,, +sqlalchemy/__pycache__/inspection.cpython-38.pyc,, +sqlalchemy/__pycache__/log.cpython-38.pyc,, +sqlalchemy/__pycache__/processors.cpython-38.pyc,, +sqlalchemy/__pycache__/schema.cpython-38.pyc,, +sqlalchemy/__pycache__/types.cpython-38.pyc,, +sqlalchemy/cimmutabledict.cpython-38-darwin.so,sha256=8pZ6vO6gj8EiR6gUUrwXwMpDMT5s7hBX3zKggYsZM3Y,37944 +sqlalchemy/connectors/__init__.py,sha256=O443ri6SrKVeRqNLMyqjX0DHFvuPxo9AdZIDkodhxwA,279 +sqlalchemy/connectors/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/connectors/__pycache__/mxodbc.cpython-38.pyc,, +sqlalchemy/connectors/__pycache__/pyodbc.cpython-38.pyc,, +sqlalchemy/connectors/mxodbc.py,sha256=EbSWZRvQFw2Ng0ec9MN4KtLJvOuTPw4lSYglho5rYL8,5784 +sqlalchemy/connectors/pyodbc.py,sha256=qVLG7itujednjC-rPVn7VWW07Mou7dDBJmNQdUhTXtk,6825 +sqlalchemy/cprocessors.cpython-38-darwin.so,sha256=XCm1qbKlZpKwzg3yT4JbiL6PihbOHfMebmqLEfoW7pQ,37352 +sqlalchemy/cresultproxy.cpython-38-darwin.so,sha256=881PewXbrI0D4mE7v7XctjCD6x8vSsbrBaKagltHJdw,41448 +sqlalchemy/databases/__init__.py,sha256=vGQM3BYXHXy6RBTFNiL80biiW3fn-LoguUjJKiFnStE,1010 +sqlalchemy/databases/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/__init__.py,sha256=66uS-lZx94aGVQvEqy_z8m1pC0P3cI-CKEWCIL2Xlsk,2085 +sqlalchemy/dialects/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/firebird/__init__.py,sha256=wZ9npV8FYElLZEYmrP1ksvN90_6YR1RkIHnT6rjxhfs,1153 +sqlalchemy/dialects/firebird/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/firebird/__pycache__/base.cpython-38.pyc,, +sqlalchemy/dialects/firebird/__pycache__/fdb.cpython-38.pyc,, +sqlalchemy/dialects/firebird/__pycache__/kinterbasdb.cpython-38.pyc,, +sqlalchemy/dialects/firebird/base.py,sha256=wUBiQwvIf35OdNUfU_Vi_rtGYeIdM7DUKogfh0KYzRY,31171 +sqlalchemy/dialects/firebird/fdb.py,sha256=w4Kc-IubUKZgY5yTcgewvzZcU2WOnuwXM94dePqbEmk,4116 +sqlalchemy/dialects/firebird/kinterbasdb.py,sha256=dQbCC8vGifRyeQhekSc_t0Zj5XKFpTH0C2XyBcxRun0,6479 +sqlalchemy/dialects/mssql/__init__.py,sha256=-tzu6QvNJpSsrB_OqbqA1WnHGJdTiFe0LRRFEBL8qiY,1788 +sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/mssql/__pycache__/base.cpython-38.pyc,, +sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-38.pyc,, +sqlalchemy/dialects/mssql/__pycache__/json.cpython-38.pyc,, +sqlalchemy/dialects/mssql/__pycache__/mxodbc.cpython-38.pyc,, +sqlalchemy/dialects/mssql/__pycache__/provision.cpython-38.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-38.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-38.pyc,, +sqlalchemy/dialects/mssql/base.py,sha256=VI2tkxGHWgfSJny29E24j3dDo2JZZniOFjpXfE4VzIg,107420 +sqlalchemy/dialects/mssql/information_schema.py,sha256=MeIFJ0gK1Um0jE1S0rG5q3cv3Mk6N_PftPUR0h7F7qU,7584 +sqlalchemy/dialects/mssql/json.py,sha256=K1RqVl5bslYyVMtk5CWGjRV_I4K1sszXjx2F_nbCVWI,4558 +sqlalchemy/dialects/mssql/mxodbc.py,sha256=QHeIbRAlNxM47dNkTaly1Qvhjoc627YsF-iTKuL_goY,4808 +sqlalchemy/dialects/mssql/provision.py,sha256=m7ofLZYZinDS91Vgs42fK7dhJNnH-J_Bw2x_tP59tCc,4255 +sqlalchemy/dialects/mssql/pymssql.py,sha256=xBkFqpSSZ2cCn4Cop6NuV4ZBN_ARVyZzh_HKpkNIRLY,4843 +sqlalchemy/dialects/mssql/pyodbc.py,sha256=WVz8xDI_xmewPc0PisBa5X7HuN6t-SVcQTYKIRLMxtk,20623 +sqlalchemy/dialects/mysql/__init__.py,sha256=2yMggm7oNcGHDrwBSBd2x7JRaYaBXl8hRHZKjW3tnuQ,2190 +sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/base.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/dml.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/expression.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/json.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/oursql.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/provision.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-38.pyc,, +sqlalchemy/dialects/mysql/__pycache__/types.cpython-38.pyc,, +sqlalchemy/dialects/mysql/aiomysql.py,sha256=KkPU83_i0CLS-bYmMcfwKKQhF7GC0zaY4_0lBojKidQ,9444 +sqlalchemy/dialects/mysql/asyncmy.py,sha256=4tiiRm3l0ncgGwf5WzVik6z-IPD-ZcLEEJx4swMy_N0,9906 +sqlalchemy/dialects/mysql/base.py,sha256=B-p9MmhsMU5H8BYV0anHO1qla2M1wTFiRzg5I0hnm_M,117932 +sqlalchemy/dialects/mysql/cymysql.py,sha256=MN5fsHApPDQxDHRPWHqSm6vznMWgxCJOtg4vEHuaMYs,2271 +sqlalchemy/dialects/mysql/dml.py,sha256=rCXGbiKl8iMi7AS30_turHWeouusLGSpSLtdHKnoUl4,6182 +sqlalchemy/dialects/mysql/enumerated.py,sha256=ZIy-3XQZtERuYv3jhvlnz5S_DCf-oiHACdgf2ymwEm4,9143 +sqlalchemy/dialects/mysql/expression.py,sha256=f_ZIA-ue7YJU3Ydq420eB5O7Q1CtS-tQUSUlM7zq7RE,3737 +sqlalchemy/dialects/mysql/json.py,sha256=JWBHb0QmE9w47gsqZyfmUQpdi8GePHutGVJQVvixigg,2313 +sqlalchemy/dialects/mysql/mariadb.py,sha256=-6FfoiYQzdaoXpTGKruuJxpB3nGTtH3DEB1EijJBLcg,500 +sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=JTocRR0zgEBy7ZC6O1JQrDT0w2zW77OfZghjgvO2514,7519 +sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=W8CL7P7hnZhmN3Pl6nwsOhwSMYvHWfCrlrWtx2F3zpU,7690 +sqlalchemy/dialects/mysql/mysqldb.py,sha256=luQwBWKAXEsodtHkvzUfKVSA86tRQjz3Ur3bI7Le57s,10520 +sqlalchemy/dialects/mysql/oursql.py,sha256=m0lhnKgGli4u_DZdsFwgz0d2iXklB4rHfacj_QfM2Tw,8523 +sqlalchemy/dialects/mysql/provision.py,sha256=P5ma4Xy5eSOFIcMjIe_zAwu_6ncSXSLVZYYSMS5Io9c,2649 +sqlalchemy/dialects/mysql/pymysql.py,sha256=n9bgdO54bO1Dp8xS61PMpKoo1RUkPngwrlxBLX0Ovts,2770 +sqlalchemy/dialects/mysql/pyodbc.py,sha256=6XXmo7LluP1IfVe3dznOiC3wSH76q-tBpCSf2L9mS7w,4498 +sqlalchemy/dialects/mysql/reflection.py,sha256=eQpTm4N5swlAginvFhbOEiuVHFVdxcPAbAwMkzcS4n8,18553 +sqlalchemy/dialects/mysql/types.py,sha256=x4SwOFKDmXmZbq88b6-dcHgo4CJzl8Np_gOsV8-0QZQ,24589 +sqlalchemy/dialects/oracle/__init__.py,sha256=a2cdiwS50KoRc0-3PrfFeTHwaw-aTb3NzGB0E60TmG8,1229 +sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/oracle/__pycache__/base.cpython-38.pyc,, +sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-38.pyc,, +sqlalchemy/dialects/oracle/__pycache__/provision.cpython-38.pyc,, +sqlalchemy/dialects/oracle/base.py,sha256=Qy_X7KNsj5pNHEsb_daViUOxDqoTYaTW59X2NRFaRU0,86866 +sqlalchemy/dialects/oracle/cx_oracle.py,sha256=24c3oUQCylpuerqWdHEzvRq3MyIclKcAiukiUTUPM9w,52734 +sqlalchemy/dialects/oracle/provision.py,sha256=enaF61XI53b92R5LBUt1CPOLUMBWI7Ulktiqs7z54Yg,5805 +sqlalchemy/dialects/postgresql/__init__.py,sha256=mpE2L4a0CMcnYHcMBGpZfm3fTpzmTMqa3NHTtQtdGTE,2509 +sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/array.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/base.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/json.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pygresql.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pypostgresql.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-38.pyc,, +sqlalchemy/dialects/postgresql/array.py,sha256=18m2Jv7DoITcNF8KGOl3Z5Ky0zB2jsPz5vo5mV_MA38,12385 +sqlalchemy/dialects/postgresql/asyncpg.py,sha256=ZshxLk8QZjcllho5YycyAh82XuQrDEfbDnJXI9171Lo,33573 +sqlalchemy/dialects/postgresql/base.py,sha256=JzwTzz2Vlcd8JwC7cmRXlbXSdSrQjLL6lO26tVA75jU,152450 +sqlalchemy/dialects/postgresql/dml.py,sha256=6fsyXbbISrWCNq4tLs-hcLpXObtv7-xcWmuNR7pSUy8,9556 +sqlalchemy/dialects/postgresql/ext.py,sha256=pcX7pfWbzIoPOFLhXFqUrSYHXVbYAAoFZ9VLg-mE4aQ,8383 +sqlalchemy/dialects/postgresql/hstore.py,sha256=mh3VhuJa8_utkAXr-ZQNMZC9c-WK8SPD43M-2OJCudE,12496 +sqlalchemy/dialects/postgresql/json.py,sha256=bK-uBXv8r4ewZqUSoF-5JGzA2JcLAwJV6vkJDZ9OTMU,10556 +sqlalchemy/dialects/postgresql/pg8000.py,sha256=aUPUc80wzEkFMJAZyKP9XKtxF9htbmiFg8-ssXiMse8,16829 +sqlalchemy/dialects/postgresql/provision.py,sha256=2hQBww2CBUz47MafjSVCVeCMoRWcCEG9fiTsKCm5KHk,4416 +sqlalchemy/dialects/postgresql/psycopg2.py,sha256=EC_Vu1py14Iz0S8qOKJE0qin7pxSLip8864BJIUzNn8,38854 +sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=lls7ZpikR4KvOQk2Nbh8z5IAT2Zu1D1Y280Mq4WQpOY,1691 +sqlalchemy/dialects/postgresql/pygresql.py,sha256=1qfzOFvEUExkvAiiFkLnVVHg6vfXGLzyp41UzBwKf24,8585 +sqlalchemy/dialects/postgresql/pypostgresql.py,sha256=3xY2pwLeYOBR7BCpj2pTtGtwcwS0VDDxM2GFmFogNPU,3693 +sqlalchemy/dialects/postgresql/ranges.py,sha256=Bfa9dLkWM51P-W_oAcnvbpUzsMg4ZrBWTN3ppi-n3Yc,4731 +sqlalchemy/dialects/sqlite/__init__.py,sha256=YQ5ryj0ZDE_3s559hsnm2cxuX2mI3ebEJ9Mf-DLmMA8,1198 +sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/base.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/json.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-38.pyc,, +sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=XBpRrOb8zD5tMmZrdLxZ3MlQKG35JfcK7Muel8Z5Yzo,9995 +sqlalchemy/dialects/sqlite/base.py,sha256=h41saLgOroxbo1wLRjkc-x7m-N1bec6KKXrXIz_s9rA,88332 +sqlalchemy/dialects/sqlite/dml.py,sha256=A60UFadXJ7erPfg6xghfPrgQwCRcOYa1EUVxmdmdd04,6839 +sqlalchemy/dialects/sqlite/json.py,sha256=oFw4Rt8xw-tkD3IMlm3TDEGe1RqrTyvIuqjABsxn8EI,2518 +sqlalchemy/dialects/sqlite/provision.py,sha256=AQILXN5PBUSM05c-SFSFFhPdFqcQDwdoKtUnvLDac14,4676 +sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=oO4myPd2OOf8ACKlyofjEV95PonyFF3l6jdXezLh9Tw,5605 +sqlalchemy/dialects/sqlite/pysqlite.py,sha256=QfvICDp6cW4myH8eMOlygSKkwv7nlfgEc5yHdB1qL4o,23441 +sqlalchemy/dialects/sybase/__init__.py,sha256=_MpFLF4UYNG1YWxabCKP5p5_a2T8aYQdGb4zOgisSjE,1364 +sqlalchemy/dialects/sybase/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/dialects/sybase/__pycache__/base.cpython-38.pyc,, +sqlalchemy/dialects/sybase/__pycache__/mxodbc.cpython-38.pyc,, +sqlalchemy/dialects/sybase/__pycache__/pyodbc.cpython-38.pyc,, +sqlalchemy/dialects/sybase/__pycache__/pysybase.cpython-38.pyc,, +sqlalchemy/dialects/sybase/base.py,sha256=eTB8YYJm5iN-52e3X89zSfXGk_b6TVjbrBMSJgjrYwU,32421 +sqlalchemy/dialects/sybase/mxodbc.py,sha256=Y3ws2Ahe8yzcnzYeclQmujCgmIMK4Lm4tWtAFmo2IaI,939 +sqlalchemy/dialects/sybase/pyodbc.py,sha256=XV9fGWBFKSalUlNtWhRqnfdPzGknrt6Yr4D8yeRRV1E,2230 +sqlalchemy/dialects/sybase/pysybase.py,sha256=8V3fvp1R52o1DLzri8kZ5LLkXp68knyJ6CkwI_mIHoo,3370 +sqlalchemy/engine/__init__.py,sha256=ZHMG_4TdVFEzXuvOAKx_yEtmVMZHnfOyUd3XGQLFivU,2075 +sqlalchemy/engine/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/base.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/characteristics.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/create.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/cursor.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/default.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/events.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/interfaces.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/mock.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/reflection.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/result.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/row.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/strategies.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/url.cpython-38.pyc,, +sqlalchemy/engine/__pycache__/util.cpython-38.pyc,, +sqlalchemy/engine/base.py,sha256=39TDFKbtZQR9VaVvWeF6sfWrrUtlZJaMeNMcrx89Xzs,118965 +sqlalchemy/engine/characteristics.py,sha256=qvd3T8HW470kIxN-x6OzycfjCFdnmbzcaFQeds7KHOw,1817 +sqlalchemy/engine/create.py,sha256=fYuff7D1cxS-dDg4_NyUHKaP66ckCrstsxC4pPkkTA4,31286 +sqlalchemy/engine/cursor.py,sha256=CIiZBqAC4TolzXHXXSwtLWgoshVT0tXJVTULeERElho,67892 +sqlalchemy/engine/default.py,sha256=OEER0s5QJo-WFm-SSPSZgPPD1gbkKleQ46MxtfIgb-s,64542 +sqlalchemy/engine/events.py,sha256=mnGuGKbF4zAxgSTVc0NHfGQvn7Vpp47pslGION-AaAU,33166 +sqlalchemy/engine/interfaces.py,sha256=ElnlzlTWNZKZaTQdQvwOff_U3Ao9tvNGssmnu0Nn5DM,60162 +sqlalchemy/engine/mock.py,sha256=37RtWX1xT7K1rem2jUtrKSynAb6HGxaq1YTW5iHAiSk,3626 +sqlalchemy/engine/reflection.py,sha256=1-bhbWt8P_1uQRD7JTdyfMKaLgvgc47UcecYOfmvoYI,38607 +sqlalchemy/engine/result.py,sha256=b5o7iS-6skI1VA7HBd8Ms0RK4BCTpXooq5-nPOl15_I,54227 +sqlalchemy/engine/row.py,sha256=uHCGnP2Buf80pQvM45-uE5znJetdVMKtjs2u2fzaXls,18191 +sqlalchemy/engine/strategies.py,sha256=mfpCWvmkLxZUW6TkJriTqCOJF7VCgDZXgzaqLsxauBc,414 +sqlalchemy/engine/url.py,sha256=m25f08HMTibiwfl1uPtjLKEeFlZ1jQ5JSqZxJoOGWZ4,26246 +sqlalchemy/engine/util.py,sha256=6FTsDDPIiS_7uC0YeamkVZyfhAEQeECgnED2Fc9IP_c,7642 +sqlalchemy/event/__init__.py,sha256=1QT0XxdMGwMMdoLzx58dUn4HqKNvzEysfKkPOluQECY,517 +sqlalchemy/event/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/event/__pycache__/api.cpython-38.pyc,, +sqlalchemy/event/__pycache__/attr.cpython-38.pyc,, +sqlalchemy/event/__pycache__/base.cpython-38.pyc,, +sqlalchemy/event/__pycache__/legacy.cpython-38.pyc,, +sqlalchemy/event/__pycache__/registry.cpython-38.pyc,, +sqlalchemy/event/api.py,sha256=yKp7BJT6pkNFvvKuBCwDJycVpwiP7aFi6xXb2QKzJxE,6794 +sqlalchemy/event/attr.py,sha256=gXcuUY3EaoWjCq2Q5Keg0O_yjmI_FvxlaCUL6ko7JgA,14625 +sqlalchemy/event/base.py,sha256=i5ud1V77ViLUQJIO_-ENEbK1VEM8lkhqmRcXrk7rZJQ,10936 +sqlalchemy/event/legacy.py,sha256=kt_rKWVIHSPQvlRSkw4NwgLf5Oz7xahXaaW-OYbmB4g,6270 +sqlalchemy/event/registry.py,sha256=pCfpcG80P6C3m-iQReVNNTc_OKQllM1CL0AAtUl_CcU,8486 +sqlalchemy/events.py,sha256=SFtMYfSRcdOmXAUvLZ_KoQfA5bHGxLW-YnaCL2xILlM,467 +sqlalchemy/exc.py,sha256=xwn6ZTC_sqg43hKJwK3-QNjaZ5AzS1F2iHRN1u1P1uI,20256 +sqlalchemy/ext/__init__.py,sha256=3eg5n6pdQubMMU1UzaNNRpSxb8e3B4fAuhpmQ3v4kx4,322 +sqlalchemy/ext/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/associationproxy.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/automap.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/baked.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/compiler.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/horizontal_shard.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/hybrid.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/indexable.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/instrumentation.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/mutable.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/orderinglist.cpython-38.pyc,, +sqlalchemy/ext/__pycache__/serializer.cpython-38.pyc,, +sqlalchemy/ext/associationproxy.py,sha256=605MuyQzOJ5KuTa8DIeiSLSl1pRRLnl-VsT63mggpUQ,49972 +sqlalchemy/ext/asyncio/__init__.py,sha256=YzmnHWOudsK1IMLNP-eCMqEkL3jvaXQRrslGczH22-4,778 +sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/ext/asyncio/__pycache__/base.cpython-38.pyc,, +sqlalchemy/ext/asyncio/__pycache__/engine.cpython-38.pyc,, +sqlalchemy/ext/asyncio/__pycache__/events.cpython-38.pyc,, +sqlalchemy/ext/asyncio/__pycache__/exc.cpython-38.pyc,, +sqlalchemy/ext/asyncio/__pycache__/result.cpython-38.pyc,, +sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-38.pyc,, +sqlalchemy/ext/asyncio/__pycache__/session.cpython-38.pyc,, +sqlalchemy/ext/asyncio/base.py,sha256=VQmIq-CMEVQpZPMEa0K91tMxZMqKyCCAwJVuCLiG34w,2280 +sqlalchemy/ext/asyncio/engine.py,sha256=ePFP7rlIfhwfWxuiA4rl3ffvDIgvUZyTXea0fHBkABk,25318 +sqlalchemy/ext/asyncio/events.py,sha256=616mp5MMyCF4OiOAp794L0tGMKmp-mTtbwukTqQ3-bo,1235 +sqlalchemy/ext/asyncio/exc.py,sha256=DwS55QWrcgoThCC3w-kE5xVnl8kUAiWm1NVcyuO0Ufs,639 +sqlalchemy/ext/asyncio/result.py,sha256=eE5nM4fzGcKD0FKg6qVnbSa8RmUKejJ96rAo7kVqdeA,20438 +sqlalchemy/ext/asyncio/scoping.py,sha256=0HA_TlXqxqGHNQnOrjhHcZgPltnfWx-lfl6drzIcETo,2874 +sqlalchemy/ext/asyncio/session.py,sha256=jGMeDJRZY87VmJLBP3dvk8F3GMgiDqSkyaHETQpjEKo,19594 +sqlalchemy/ext/automap.py,sha256=JJqJDyPp9p7sl4htcDG_RWBdPAE6SOfxTlGFO0bAcFU,45195 +sqlalchemy/ext/baked.py,sha256=OzOdFF9Wvz9sflF2EYlIEHP9tKbVn3x8K6pEEgM4Kg4,19969 +sqlalchemy/ext/compiler.py,sha256=XnPSC8_mQTSYTXOSegt0-XpPxZXzJHyTCpQvdVG-WtE,17989 +sqlalchemy/ext/declarative/__init__.py,sha256=M4hGt8MVZzjVespP-G_3lUP1oCk9rev_xN5AjSgB6TU,1842 +sqlalchemy/ext/declarative/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/ext/declarative/__pycache__/extensions.cpython-38.pyc,, +sqlalchemy/ext/declarative/extensions.py,sha256=bNylndJ-MdWBC1gn5dS5WUzgfvsDT-0r1Gqfl6EUAJI,16409 +sqlalchemy/ext/horizontal_shard.py,sha256=KuqRl1GStQmcAfJ2bFf08kbV8Dktx1jYZ_ogf_FZAkI,8922 +sqlalchemy/ext/hybrid.py,sha256=8sdaB6aFHN590EU9FBV2oT8fHz14J5TMYZKoRDMFsWo,41901 +sqlalchemy/ext/indexable.py,sha256=mOjILC84bSHxehal-E893YJLEELTYPz7MD8DHIRFCr4,11255 +sqlalchemy/ext/instrumentation.py,sha256=ReSLFxqbHgwAKNwoQQmKHoqYvWCob_WuXlPAEUJk4pk,14386 +sqlalchemy/ext/mutable.py,sha256=3ZfxmQoctFchZNGJppg-bzxPPSLvLcGKt_k6AQgDTXI,31997 +sqlalchemy/ext/mypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/ext/mypy/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/ext/mypy/__pycache__/apply.cpython-38.pyc,, +sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-38.pyc,, +sqlalchemy/ext/mypy/__pycache__/infer.cpython-38.pyc,, +sqlalchemy/ext/mypy/__pycache__/names.cpython-38.pyc,, +sqlalchemy/ext/mypy/__pycache__/plugin.cpython-38.pyc,, +sqlalchemy/ext/mypy/__pycache__/util.cpython-38.pyc,, +sqlalchemy/ext/mypy/apply.py,sha256=z42HLeqy5Hh9v--2ohql16fa5Lbsas0UZMYeraovq6w,9503 +sqlalchemy/ext/mypy/decl_class.py,sha256=D_12pRqsO5lLw_FovRrDAykbeEirv4l2wuWLMHyWA1c,16698 +sqlalchemy/ext/mypy/infer.py,sha256=JBS3N-gvK7jHorWs2EYNpiRj9MmBRT6cpg7CX6pb-no,17743 +sqlalchemy/ext/mypy/names.py,sha256=CZjTn0YTsR-XN7gMBD-D39PolKQsDQCwcjk9loAoM5M,7687 +sqlalchemy/ext/mypy/plugin.py,sha256=HTyHlZeSzcUMT86TTpcjWOsXCe128k1ZJoLIPgU56qU,9223 +sqlalchemy/ext/mypy/util.py,sha256=z1z8UewpjK7xC9Kl8wFooikNn7xbQiMrYJHkTTwxJog,8149 +sqlalchemy/ext/orderinglist.py,sha256=pAhYXNDVm0o0ZuxtbmGFan3Fw8zhpJhiRPmrndzM-_8,13875 +sqlalchemy/ext/serializer.py,sha256=i2HZTt9O-PxidEXZKb9iDqJO3F0uhQ4w6Ens48wM6gY,5956 +sqlalchemy/future/__init__.py,sha256=b1swUP9MZmoZx3VXv6aQ2L9JB5iThBQe09SviZP8HYo,525 +sqlalchemy/future/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/future/__pycache__/engine.cpython-38.pyc,, +sqlalchemy/future/engine.py,sha256=_yFJPyFi22UMSfO8gn2kv18VVB_xbRMqiUZb6mdtxU4,16567 +sqlalchemy/future/orm/__init__.py,sha256=Fj72ozD2mgP9R9t8E6vWarr5USz_5AUx7BqWLEld84w,289 +sqlalchemy/future/orm/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/inspection.py,sha256=EqHUnvpjuwiPUIdD92autVgiO2YAgC-yX9Trk1m5oSA,3051 +sqlalchemy/log.py,sha256=G-jGx-_08ZUS2J3djgTgt-coqb4fngSl6ehYaF7nmYE,6770 +sqlalchemy/orm/__init__.py,sha256=owW9Arnd-13KJRHVMNR6kScqmAQYVboGUJqP3MpE22k,10480 +sqlalchemy/orm/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/attributes.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/base.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/clsregistry.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/collections.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/context.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/decl_api.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/decl_base.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/dependency.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/descriptor_props.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/dynamic.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/evaluator.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/events.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/exc.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/identity.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/instrumentation.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/interfaces.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/loading.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/mapper.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/path_registry.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/persistence.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/properties.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/query.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/relationships.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/scoping.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/session.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/state.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/strategies.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/strategy_options.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/sync.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/unitofwork.cpython-38.pyc,, +sqlalchemy/orm/__pycache__/util.cpython-38.pyc,, +sqlalchemy/orm/attributes.py,sha256=-wzQhvx7ebUXcTWLlSo5yNNIXlVYEO-v3UJSrNF07ow,76590 +sqlalchemy/orm/base.py,sha256=Nuo2suXVjo_GPl7p5alHe9o5862VtXQ7Mv2IEx2r-fQ,15068 +sqlalchemy/orm/clsregistry.py,sha256=POxg7BYwk8FkuMHPi8dmgBpCGSY3RzMdOm0iHJBLAcY,13291 +sqlalchemy/orm/collections.py,sha256=b6wKDA6IKCkItw6gKOmFfjXv7-UUrPXi8UaIWb8S2M4,54711 +sqlalchemy/orm/context.py,sha256=qMMS2p_WKFYOO2rnyBDXw9N_ujhpSc6Sdo40eq5Neoc,105059 +sqlalchemy/orm/decl_api.py,sha256=_eLE7TI3omhAKv_X_4nHZzkdFnntlpNLLMczBeKKcz8,34976 +sqlalchemy/orm/decl_base.py,sha256=LMv7fJ64ZzYRViw7h1_3cqyspO0L4lIouVmAj_8oVhQ,42695 +sqlalchemy/orm/dependency.py,sha256=lLqfIMcBWk4ot9qhrNjoOce5-m0ciJSHJtPX5oHwGHs,46987 +sqlalchemy/orm/descriptor_props.py,sha256=nXZLDtLH1Q7gxXBJhPgz3g0K03zSm2plC-VkdCdLRNQ,25958 +sqlalchemy/orm/dynamic.py,sha256=lKXKi3VlFFLYvTLGxQBovSs_87wn1Nb5BwiG5AieMug,15819 +sqlalchemy/orm/evaluator.py,sha256=dwZ9jDx4Ooay0lBs2mL5RjLj2fisUaNrwFWkYJtsS1Y,6852 +sqlalchemy/orm/events.py,sha256=xKIVaKg14lk1o3s4NWtIuAUnQw3ZPHP92Ve5zb_zCZg,110251 +sqlalchemy/orm/exc.py,sha256=3HLZcpE8ESh37Mzx711_PMhgQLUPzy2bX1-RVA2o8xw,6532 +sqlalchemy/orm/identity.py,sha256=LqfTEkoQNaA2pYpn-94QZ1QDSdOjg1fjAVRb86zh_Os,6801 +sqlalchemy/orm/instrumentation.py,sha256=-BxrpgaW-pznyd-9bsRM8ns69fGaojdO5qAxnHHz5Pw,20349 +sqlalchemy/orm/interfaces.py,sha256=5v0ic5M10zc13KAT_et-W7ZPpBESOrNqTUZ2mPL1eUk,28455 +sqlalchemy/orm/loading.py,sha256=tL09EMBOoKW0wUI-avuhiTob4hTP1AtCMdVoVI5CGmY,49131 +sqlalchemy/orm/mapper.py,sha256=1AVOjje8hFwukSFOmTXtJrYujGnCHkLKntD2VX6xOHQ,136193 +sqlalchemy/orm/path_registry.py,sha256=E2ta4R8qKA8JvMAM83JG0DWsDdGnFF9bfQyHtxehW_4,15108 +sqlalchemy/orm/persistence.py,sha256=2svOrY6q0Ci_C8PNuDWIrpKwr2Dxt4v6xx1pb0Z3Ujk,79037 +sqlalchemy/orm/properties.py,sha256=4qUYr0ShU_z5rofa0X2f78j6G1miThpxi3ap8CW_1ag,14883 +sqlalchemy/orm/query.py,sha256=ejCeNpTqwggVeMv5a3MozYkYy89fsFvN3jkTZpOOv5o,121879 +sqlalchemy/orm/relationships.py,sha256=pJ8UzBGPHQfDTt4cV7U7_FztOO73ZroQPOpzZRYrp_w,143028 +sqlalchemy/orm/scoping.py,sha256=_2F6a2U_yBLaqpgK6TU1V1EELir2tHX_sDbd4_E13HY,7201 +sqlalchemy/orm/session.py,sha256=rorVbMqcefyfUyguugfeSjs1qZiP6KzPRAWrNQTQPMU,158520 +sqlalchemy/orm/state.py,sha256=actQlG4fvVtEapQxIObZDw6T5wfPPCCnDxwIaW51OUs,33409 +sqlalchemy/orm/strategies.py,sha256=66n-9t2iD4Bjb6jUAetnbNL4Y5kDoO_99inLZfb9Xc8,107325 +sqlalchemy/orm/strategy_options.py,sha256=NpwcZR6NTEUC4rAJTD2W_wkBNYu2PGaG4iOKC5JOytI,66751 +sqlalchemy/orm/sync.py,sha256=tE2dS0i3vekS1TfB7R-_hhvekOi_esfcB-0bSwajjck,5824 +sqlalchemy/orm/unitofwork.py,sha256=nRJ7fWzpiedk5ObQz2v5gojLBzml9W5Al4qNB6-JWoI,27090 +sqlalchemy/orm/util.py,sha256=dursgRL1gTecOAr05cgjn60wjNOA0Ve8cjVAbK-XkUc,69034 +sqlalchemy/pool/__init__.py,sha256=cQIwYAY52VyVgAKdA159zhdlS38Dy6fFWT7l-KWjubk,1603 +sqlalchemy/pool/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/pool/__pycache__/base.cpython-38.pyc,, +sqlalchemy/pool/__pycache__/dbapi_proxy.cpython-38.pyc,, +sqlalchemy/pool/__pycache__/events.cpython-38.pyc,, +sqlalchemy/pool/__pycache__/impl.cpython-38.pyc,, +sqlalchemy/pool/base.py,sha256=vKBUGS59GwHjbQu-9ZFLzRbAqowTa-UgL9pjPKnUwYg,38552 +sqlalchemy/pool/dbapi_proxy.py,sha256=mPGtLr9czWrlVm2INYS1yMDr8bx-8rxY4KbAKmAasTk,4229 +sqlalchemy/pool/events.py,sha256=Z4LB7zGyEh-6L5VcWLdSdZ9lfOgDnn_G939Y_Fx_Wc8,10046 +sqlalchemy/pool/impl.py,sha256=VpW58L1fSxPtXWAzPvZ8qFhDRd_QiLdXN5GcjG68KP4,15783 +sqlalchemy/processors.py,sha256=ZnVfpn3-SQyqBa-3bmrjVPu3WyB7wsCovqRAeQdOP0M,5745 +sqlalchemy/schema.py,sha256=SbqBYd5vstujoWgpBXav9hBz7uUernJlhDTMFE05b4s,2413 +sqlalchemy/sql/__init__.py,sha256=E8Itj6nV7prc9wxhZiLBNghWLgG-MplZv_K3kxPltfc,4661 +sqlalchemy/sql/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/annotation.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/base.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/coercions.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/compiler.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/crud.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/ddl.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/default_comparator.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/dml.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/elements.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/events.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/expression.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/functions.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/lambdas.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/naming.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/operators.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/roles.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/schema.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/selectable.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/sqltypes.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/traversals.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/type_api.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/util.cpython-38.pyc,, +sqlalchemy/sql/__pycache__/visitors.cpython-38.pyc,, +sqlalchemy/sql/annotation.py,sha256=90IWQimMll92PwzUzP1I0zX_DQBSreciHZspCIj1Hro,11235 +sqlalchemy/sql/base.py,sha256=WhH4gBGmEHUXdgaIDvjCMn3b2lM_VTnKMHee6W59d3w,55100 +sqlalchemy/sql/coercions.py,sha256=6q8OkiHGtl1tjeTPKxpZ4QIuHrv-L35hDytJjt9jMTU,32987 +sqlalchemy/sql/compiler.py,sha256=KyZGEDOZVOylYXSLBpOReT0ZsTDPsJllyvTrukadPyQ,181529 +sqlalchemy/sql/crud.py,sha256=LvT3ktKZ1eRvA85k_xXdP2ReU8-EWRYFMJhk-B0uRmc,35420 +sqlalchemy/sql/ddl.py,sha256=mHHvmrcCuLhU3B5FitlOzN_2OTer4NX2lIUUPwRlp7U,44002 +sqlalchemy/sql/default_comparator.py,sha256=3LnJPlCTdCawg-XFcJHhCUWEMbfDFw8svXDyzEcsCfg,10882 +sqlalchemy/sql/dml.py,sha256=T2vpeljRwPuMRaVvvTa8DMitmWjnNPqREtACzVeFk6A,52008 +sqlalchemy/sql/elements.py,sha256=hlE6D1M1uox8gQyB0i3oQaDLfO6snZlZUEUdDxdNVZ0,175933 +sqlalchemy/sql/events.py,sha256=_OSPvVSGVd3ex1KI-m5eeULXoTm-EhEUEN_KKuDGTsM,13087 +sqlalchemy/sql/expression.py,sha256=U4nrgSoREcBFP9gjaT2SZByHsls4JS1TIBpobKv1Y7c,8828 +sqlalchemy/sql/functions.py,sha256=bZVBP3oNRQUHZOqVtXHeEywJZKWWfVoGLdg-Kdwau1Q,47344 +sqlalchemy/sql/lambdas.py,sha256=vl2xjN6EgnzIPVDDqDhMw7M7LMK1QvMfJ3Bvw2XDl7c,44238 +sqlalchemy/sql/naming.py,sha256=G1eXvRjbZ8QENRaOhSIj_8ZFAiqeqe4hHPpBKktXmns,6786 +sqlalchemy/sql/operators.py,sha256=kqSj7DMjj0ZNboH6dOi3Zbg1ZOsiNec3JHcxiNzXpoc,47766 +sqlalchemy/sql/roles.py,sha256=fpar1bXMzfLTOGc0KRxCPeu8wB8f9Gt5Pi1ViSH185c,5457 +sqlalchemy/sql/schema.py,sha256=oyHdkA-MBDUM9Nt4_OaoZG7qO0H-ec14SLBdr7b1NZ0,186979 +sqlalchemy/sql/selectable.py,sha256=DDeKRa_XjkDostYh6QF7tDDdRqmV1dKRv4bVWhjRf-s,228890 +sqlalchemy/sql/sqltypes.py,sha256=nt2kocZcH1AJY3dqWU92CwcQPcnt9XmmkpIbbDCrfxI,111103 +sqlalchemy/sql/traversals.py,sha256=vgbnT_A8cSgf5a23IXn8Qj3HkJJ2rpvIhyWLqLKeDco,49443 +sqlalchemy/sql/type_api.py,sha256=39U5YRUbk8hyWMjf725l1GkF07_zJL82qWN_D1Mq93U,57718 +sqlalchemy/sql/util.py,sha256=5GMeMsBp-A5vLnSLdx1kCd46dD7XHJ6ieJTZk6sQruo,34450 +sqlalchemy/sql/visitors.py,sha256=uPsWctSGvEC77lCGO2SgrIs6GONnIT0kkU6--SMrHvc,27316 +sqlalchemy/testing/__init__.py,sha256=2r5jKsKug5mSBWqc8szFQZjT-SEQ0S00ZUkDhvMaGaE,2768 +sqlalchemy/testing/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/assertions.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/assertsql.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/asyncio.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/config.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/engines.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/entities.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/exclusions.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/fixtures.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/mock.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/pickleable.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/profiling.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/provision.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/requirements.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/schema.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/util.cpython-38.pyc,, +sqlalchemy/testing/__pycache__/warnings.cpython-38.pyc,, +sqlalchemy/testing/assertions.py,sha256=8TppHFen5R9lMi9jLjj5PtBqg6bty9QopkyUgrB54Jg,23705 +sqlalchemy/testing/assertsql.py,sha256=VDeFE6B6MUOsW46Wjpef48ypTfbkwx1glm6ExuiZ28g,14964 +sqlalchemy/testing/asyncio.py,sha256=ffDzERQV3g2cpylQHdfuc1ZveK7v_Q8240cCdsaEFAk,3672 +sqlalchemy/testing/config.py,sha256=BokuYTNp-Nkcjb-x_IaF-FU869ONJE3k_wv52n7ojZ4,6543 +sqlalchemy/testing/engines.py,sha256=XOHhutDz2RHqfuVtzQxNlgrY4T8n5QqlwK4YOcdvZZs,12661 +sqlalchemy/testing/entities.py,sha256=lxagTVr0pqQb14fr3-pdpbHXSxlbYh5UK-jLazQcd3Q,3253 +sqlalchemy/testing/exclusions.py,sha256=i-QZY81gdxRQZ-TF5I_I2Q6P4iSJqPCIdCMpNVwAvTE,13329 +sqlalchemy/testing/fixtures.py,sha256=0oYnGOdfrjHUnf4NHC46Jo8kOSj0QAtOlUpz0g6VXH4,25204 +sqlalchemy/testing/mock.py,sha256=bw0Ds9eMMBHEDzT6shKJxi-9fFMH6qB9D00QxedH4OY,894 +sqlalchemy/testing/pickleable.py,sha256=0Rfbbtj7LJIsYOKo_cbByUC4FnXYXLiXwHl1VwrtcW8,2707 +sqlalchemy/testing/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/testing/plugin/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-38.pyc,, +sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-38.pyc,, +sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-38.pyc,, +sqlalchemy/testing/plugin/__pycache__/reinvent_fixtures_py2k.cpython-38.pyc,, +sqlalchemy/testing/plugin/bootstrap.py,sha256=8XJMcCyKMkC5cYDU9r9gZg5eNSZZGYCjS7eiUU3hHrk,1688 +sqlalchemy/testing/plugin/plugin_base.py,sha256=X31fT9gFLi1xZgS9AeaM3qI7K3qKk1rLvGoph8ajOCM,21561 +sqlalchemy/testing/plugin/pytestplugin.py,sha256=dNAyrUUMxLMdbNB4_bVg4E-BW-NZsRre_yalIHPCyEA,25533 +sqlalchemy/testing/plugin/reinvent_fixtures_py2k.py,sha256=MdakbJzFh8N_7gUpX-nFbGPFs3AZRsmDAe-7zucf0ls,3288 +sqlalchemy/testing/profiling.py,sha256=q_4rhjMpb0nWBZ7K_JkuQMLKPcI-1kiB27_EKI49CDw,10566 +sqlalchemy/testing/provision.py,sha256=YUEX9eiHBnQYpTHKBWM9IBMoVRFIgm6sjcZIqOeyKIc,12047 +sqlalchemy/testing/requirements.py,sha256=UJmZCY2-rOqNz0Rjj-AF5sN4tZGvDgPL4MGl_nuvGZk,41470 +sqlalchemy/testing/schema.py,sha256=0IHnIuEHYMqjdSIjMkn7dUKSZoWbY7ou4SWGQY5X13o,6544 +sqlalchemy/testing/suite/__init__.py,sha256=_firVc2uS3TMZ3vH2baQzNb17ubM78RHtb9kniSybmk,476 +sqlalchemy/testing/suite/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_cte.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_insert.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_results.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_select.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_types.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-38.pyc,, +sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-38.pyc,, +sqlalchemy/testing/suite/test_cte.py,sha256=XuTuaWblSXyO1OOUTShBBmNch7fBdGnlMD84ooVTqFY,6183 +sqlalchemy/testing/suite/test_ddl.py,sha256=UwbfljXHdWUen3muIcgnOPi-A4AO6F1QzSOiHf9lU-A,11762 +sqlalchemy/testing/suite/test_deprecations.py,sha256=8oLDFUswey8KjPFKRUsqMyGT5sUMMoPQr7-XyIBMehw,5059 +sqlalchemy/testing/suite/test_dialect.py,sha256=eR1VVOb2fm955zavpWkmMjipCva3QvEE177U0OG-0LY,10895 +sqlalchemy/testing/suite/test_insert.py,sha256=oKtVjFuxqdSV5uKj5-OxdSABupLp0pECkWkSLd2U_QA,11134 +sqlalchemy/testing/suite/test_reflection.py,sha256=hGZAws3gDZ3k-8WCbPJ52oHQYJpC0Lg-OiwZBrvHWAY,55164 +sqlalchemy/testing/suite/test_results.py,sha256=xcoSl1ueaHo8LgKZp0Z1lJ44Mhjf2hxlWs_LjNLBNiE,13983 +sqlalchemy/testing/suite/test_rowcount.py,sha256=GQQRXIWbb6SfD5hwtBC8qvkGAgi1rI5Pv3c59eoumck,4877 +sqlalchemy/testing/suite/test_select.py,sha256=kOUoATq1oQZeTrvlGw1JXbfCn5CafSObFq2iIsnYAwI,52397 +sqlalchemy/testing/suite/test_sequence.py,sha256=eCyOQlynF8T0cLrIMz0PO6WuW8ktpFVYq_fQp5CQ298,8431 +sqlalchemy/testing/suite/test_types.py,sha256=i6mP3HTnzXw_Y_z8MyWUV4E7lTdI0wvmAw2jdMCrB0Y,45607 +sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=CndeAtV3DWJXxLbOoumqf4_mOOYcW_yNOrbKQ4cwFhw,6737 +sqlalchemy/testing/suite/test_update_delete.py,sha256=ebU5oV9hUZCW1ZBaZ-YAnxQE2Nk6GQashkOy6FOsp_c,1587 +sqlalchemy/testing/util.py,sha256=ZtMew3LnhnKuL8V7oeQ9YC5rv4ZExSKdKh5VxVyjDj0,12503 +sqlalchemy/testing/warnings.py,sha256=5SkrZoSFK1-i0FbMp5Uo_fvmxLSibjxE-bZ82NFnCag,4505 +sqlalchemy/types.py,sha256=GvShxeY8sqWDkAbfhfIncsOstCtarPPHCWggFHNoGj4,2883 +sqlalchemy/util/__init__.py,sha256=mIaf4TsiXudtmChnsKbcX1OJNRE4Cqp8H-7CQmk_rnE,6314 +sqlalchemy/util/__pycache__/__init__.cpython-38.pyc,, +sqlalchemy/util/__pycache__/_collections.cpython-38.pyc,, +sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-38.pyc,, +sqlalchemy/util/__pycache__/_preloaded.cpython-38.pyc,, +sqlalchemy/util/__pycache__/compat.cpython-38.pyc,, +sqlalchemy/util/__pycache__/concurrency.cpython-38.pyc,, +sqlalchemy/util/__pycache__/deprecations.cpython-38.pyc,, +sqlalchemy/util/__pycache__/langhelpers.cpython-38.pyc,, +sqlalchemy/util/__pycache__/queue.cpython-38.pyc,, +sqlalchemy/util/__pycache__/topological.cpython-38.pyc,, +sqlalchemy/util/_collections.py,sha256=BhJPIHmzZ56K35OdqUhxueitkG-_DXqq2VfNggPzD4U,29139 +sqlalchemy/util/_concurrency_py3k.py,sha256=DstoILbB9p6nLhJjk7ZXBG_h6ch2VlRXFAvJFiSStU8,8487 +sqlalchemy/util/_preloaded.py,sha256=SGizwMVpZcVk_4OFVBkYuB1ISaySciSstyel8OAptIk,2396 +sqlalchemy/util/compat.py,sha256=tk5GQ_Wh6DhUJ35FpbUfH9f-pVMMFi54Q8URlpYEOsI,18245 +sqlalchemy/util/concurrency.py,sha256=xxPVZnLW5oxCIRYMj-Zh5TVhcURCSa2j0vk84Cn0WsA,1911 +sqlalchemy/util/deprecations.py,sha256=FWth36W4iwIAe_h98iBj8KxJ4F8jRk7Bq66MxkCHpNQ,11490 +sqlalchemy/util/langhelpers.py,sha256=FxMJByLfGzagAkHqSGofTCN8GVSOmahtkuH1z_16Trw,56250 +sqlalchemy/util/queue.py,sha256=WvS8AimNmR8baB-QDbHJe9F4RT9e05bYLxiVPouzNLk,9293 +sqlalchemy/util/topological.py,sha256=FtPkCjm8J6RU3sHZqM5AmQZCsqHfGfugu41pU8GS35k,2859 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/WHEEL new file mode 100644 index 000000000..d5e85bd31 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: false +Tag: cp38-cp38-macosx_10_14_x86_64 + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/top_level.txt new file mode 100644 index 000000000..39fb2befb --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/SQLAlchemy-1.4.25.dist-info/top_level.txt @@ -0,0 +1 @@ +sqlalchemy diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/LICENSE.rst b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/LICENSE.rst new file mode 100644 index 000000000..c37cae49e --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/METADATA new file mode 100644 index 000000000..f991d5aa3 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/METADATA @@ -0,0 +1,128 @@ +Metadata-Version: 2.1 +Name: Werkzeug +Version: 2.0.1 +Summary: The comprehensive WSGI web application library. +Home-page: https://palletsprojects.com/p/werkzeug/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://werkzeug.palletsprojects.com/ +Project-URL: Changes, https://werkzeug.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/werkzeug/ +Project-URL: Issue Tracker, https://github.com/pallets/werkzeug/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +Requires-Dist: dataclasses ; python_version < "3.7" +Provides-Extra: watchdog +Requires-Dist: watchdog ; extra == 'watchdog' + +Werkzeug +======== + +*werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff") + +Werkzeug is a comprehensive `WSGI`_ web application library. It began as +a simple collection of various utilities for WSGI applications and has +become one of the most advanced WSGI utility libraries. + +It includes: + +- An interactive debugger that allows inspecting stack traces and + source code in the browser with an interactive interpreter for any + frame in the stack. +- A full-featured request object with objects to interact with + headers, query args, form data, files, and cookies. +- A response object that can wrap other WSGI applications and handle + streaming data. +- A routing system for matching URLs to endpoints and generating URLs + for endpoints, with an extensible system for capturing variables + from URLs. +- HTTP utilities to handle entity tags, cache control, dates, user + agents, cookies, files, and more. +- A threaded WSGI server for use while developing applications + locally. +- A test client for simulating HTTP requests during testing without + requiring running a server. + +Werkzeug doesn't enforce any dependencies. It is up to the developer to +choose a template engine, database adapter, and even how to handle +requests. It can be used to build all sorts of end user applications +such as blogs, wikis, or bulletin boards. + +`Flask`_ wraps Werkzeug, using it to handle the details of WSGI while +providing more structure and patterns for defining powerful +applications. + +.. _WSGI: https://wsgi.readthedocs.io/en/latest/ +.. _Flask: https://www.palletsprojects.com/p/flask/ + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U Werkzeug + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +A Simple Example +---------------- + +.. code-block:: python + + from werkzeug.wrappers import Request, Response + + @Request.application + def application(request): + return Response('Hello, World!') + + if __name__ == '__main__': + from werkzeug.serving import run_simple + run_simple('localhost', 4000, application) + + +Donate +------ + +The Pallets organization develops and supports Werkzeug and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://werkzeug.palletsprojects.com/ +- Changes: https://werkzeug.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Werkzeug/ +- Source Code: https://github.com/pallets/werkzeug/ +- Issue Tracker: https://github.com/pallets/werkzeug/issues/ +- Website: https://palletsprojects.com/p/werkzeug/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/RECORD new file mode 100644 index 000000000..b691f8da3 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/RECORD @@ -0,0 +1,111 @@ +Werkzeug-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Werkzeug-2.0.1.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Werkzeug-2.0.1.dist-info/METADATA,sha256=8-W33EMnGqnCCi-d8Dv63IQQuyELRIsXhwOJNXbNgL0,4421 +Werkzeug-2.0.1.dist-info/RECORD,, +Werkzeug-2.0.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +Werkzeug-2.0.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +werkzeug/__init__.py,sha256=_CCsfdeqNllFNRJx8cvqYrwBsQQQXJaMmnk2sAZnDng,188 +werkzeug/__pycache__/__init__.cpython-38.pyc,, +werkzeug/__pycache__/_internal.cpython-38.pyc,, +werkzeug/__pycache__/_reloader.cpython-38.pyc,, +werkzeug/__pycache__/datastructures.cpython-38.pyc,, +werkzeug/__pycache__/exceptions.cpython-38.pyc,, +werkzeug/__pycache__/filesystem.cpython-38.pyc,, +werkzeug/__pycache__/formparser.cpython-38.pyc,, +werkzeug/__pycache__/http.cpython-38.pyc,, +werkzeug/__pycache__/local.cpython-38.pyc,, +werkzeug/__pycache__/routing.cpython-38.pyc,, +werkzeug/__pycache__/security.cpython-38.pyc,, +werkzeug/__pycache__/serving.cpython-38.pyc,, +werkzeug/__pycache__/test.cpython-38.pyc,, +werkzeug/__pycache__/testapp.cpython-38.pyc,, +werkzeug/__pycache__/urls.cpython-38.pyc,, +werkzeug/__pycache__/user_agent.cpython-38.pyc,, +werkzeug/__pycache__/useragents.cpython-38.pyc,, +werkzeug/__pycache__/utils.cpython-38.pyc,, +werkzeug/__pycache__/wsgi.cpython-38.pyc,, +werkzeug/_internal.py,sha256=_QKkvdaG4pDFwK68c0EpPzYJGe9Y7toRAT1cBbC-CxU,18572 +werkzeug/_reloader.py,sha256=B1hEfgsUOz2IginBQM5Zak_eaIF7gr3GS5-0x2OHvAE,13950 +werkzeug/datastructures.py,sha256=KahVPSLOapbNbKh1ppr9K8_DgWJv1EGgA9DhTEGMHcg,97886 +werkzeug/datastructures.pyi,sha256=5DTPF8P8Zvi458eK27Qcj7eNUlLM_AC0jBNkj6uQpds,33774 +werkzeug/debug/__init__.py,sha256=CUFrPEYAaotHRkmjOieqd3EasXDii2JVC1HdmEzMwqM,17924 +werkzeug/debug/__pycache__/__init__.cpython-38.pyc,, +werkzeug/debug/__pycache__/console.cpython-38.pyc,, +werkzeug/debug/__pycache__/repr.cpython-38.pyc,, +werkzeug/debug/__pycache__/tbtools.cpython-38.pyc,, +werkzeug/debug/console.py,sha256=E1nBMEvFkX673ShQjPtVY-byYatfX9MN-dBMjRI8a8E,5897 +werkzeug/debug/repr.py,sha256=QCSHENKsChEZDCIApkVi_UNjhJ77v8BMXK1OfxO189M,9483 +werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673 +werkzeug/debug/shared/ICON_LICENSE.md,sha256=DhA6Y1gUl5Jwfg0NFN9Rj4VWITt8tUx0IvdGf0ux9-s,222 +werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507 +werkzeug/debug/shared/debugger.js,sha256=dYbUmFmb3YZb5YpWpYPOQArdrN7NPeY0ODawL7ihzDI,10524 +werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191 +werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200 +werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818 +werkzeug/debug/shared/style.css,sha256=vyp1RnB227Fuw8LIyM5C-bBCBQN5hvZSCApY2oeJ9ik,6705 +werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220 +werkzeug/debug/tbtools.py,sha256=TfReusPbM3yjm3xvOFkH45V7-5JnNqB9x1EQPnVC6Xo,19189 +werkzeug/exceptions.py,sha256=CUwx0pBiNbk4f9cON17ekgKnmLi6HIVFjUmYZc2x0wM,28681 +werkzeug/filesystem.py,sha256=JS2Dv2QF98WILxY4_thHl-WMcUcwluF_4igkDPaP1l4,1956 +werkzeug/formparser.py,sha256=GIKfzuQ_khuBXnf3N7_LzOEruYwNc3m4bI02BgtT5jg,17385 +werkzeug/http.py,sha256=oUCXFFMnkOQ-cHbUY_aiqitshcrSzNDq3fEMf1VI_yk,45141 +werkzeug/local.py,sha256=WsR6H-2XOtPigpimjORbLsS3h9WI0lCdZjGI2LHDDxA,22733 +werkzeug/middleware/__init__.py,sha256=qfqgdT5npwG9ses3-FXQJf3aB95JYP1zchetH_T3PUw,500 +werkzeug/middleware/__pycache__/__init__.cpython-38.pyc,, +werkzeug/middleware/__pycache__/dispatcher.cpython-38.pyc,, +werkzeug/middleware/__pycache__/http_proxy.cpython-38.pyc,, +werkzeug/middleware/__pycache__/lint.cpython-38.pyc,, +werkzeug/middleware/__pycache__/profiler.cpython-38.pyc,, +werkzeug/middleware/__pycache__/proxy_fix.cpython-38.pyc,, +werkzeug/middleware/__pycache__/shared_data.cpython-38.pyc,, +werkzeug/middleware/dispatcher.py,sha256=Fh_w-KyWnTSYF-Lfv5dimQ7THSS7afPAZMmvc4zF1gg,2580 +werkzeug/middleware/http_proxy.py,sha256=HE8VyhS7CR-E1O6_9b68huv8FLgGGR1DLYqkS3Xcp3Q,7558 +werkzeug/middleware/lint.py,sha256=yMzMdm4xI2_N-Wv2j1yoaVI3ltHOYS6yZyA-wUv1sKw,13962 +werkzeug/middleware/profiler.py,sha256=G2JieUMv4QPamtCY6ibIK7P-piPRdPybav7bm2MSFvs,4898 +werkzeug/middleware/proxy_fix.py,sha256=uRgQ3dEvFV8JxUqajHYYYOPEeA_BFqaa51Yp8VW0uzA,6849 +werkzeug/middleware/shared_data.py,sha256=eOCGr-i6BCexDfL7xdPRWMwPJPgp0NE2B416Gl67Q78,10959 +werkzeug/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/routing.py,sha256=FDRtvCfaZSmXnQ0cUYxowb3P0y0dxlUlMSUmerY5sb0,84147 +werkzeug/sansio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/sansio/__pycache__/__init__.cpython-38.pyc,, +werkzeug/sansio/__pycache__/multipart.cpython-38.pyc,, +werkzeug/sansio/__pycache__/request.cpython-38.pyc,, +werkzeug/sansio/__pycache__/response.cpython-38.pyc,, +werkzeug/sansio/__pycache__/utils.cpython-38.pyc,, +werkzeug/sansio/multipart.py,sha256=bJMCNC2f5xyAaylahNViJ0JqmV4ThLRbDVGVzKwcqrQ,8751 +werkzeug/sansio/request.py,sha256=aA9rABkWiG4MhYMByanst2NXkEclsq8SIxhb0LQf0e0,20228 +werkzeug/sansio/response.py,sha256=HSG6t-tyPZd3awzWqr7qL9IV4HYAvDgON1c0YPU2RXw,24117 +werkzeug/sansio/utils.py,sha256=V5v-UUnX8pm4RehP9Tt_NiUSOJGJGUvKjlW0eOIQldM,4164 +werkzeug/security.py,sha256=gPDRuCjkjWrcqj99tBMq8_nHFZLFQjgoW5Ga5XIw9jo,8158 +werkzeug/serving.py,sha256=_RG2dCclOQcdjJ2NE8tzCRybGePlwcs8kTypiWRP2gY,38030 +werkzeug/test.py,sha256=EJXJy-b_JriHrlfs5VNCkwbki8Kn_xUDkOYOCx_6Q7Q,48096 +werkzeug/testapp.py,sha256=f48prWSGJhbSrvYb8e1fnAah4BkrLb0enHSdChgsjBY,9471 +werkzeug/urls.py,sha256=3o_aUcr5Ou13XihSU6VvX6RHMhoWkKpXuCCia9SSAb8,41021 +werkzeug/user_agent.py,sha256=WclZhpvgLurMF45hsioSbS75H1Zb4iMQGKN3_yZ2oKo,1420 +werkzeug/useragents.py,sha256=G8tmv_6vxJaPrLQH3eODNgIYe0_V6KETROQlJI-WxDE,7264 +werkzeug/utils.py,sha256=WrU-LbwemyGd8zBHBgQyLaIxing4QLEChiP0qnzr2sc,36771 +werkzeug/wrappers/__init__.py,sha256=-s75nPbyXHzU_rwmLPDhoMuGbEUk0jZT_n0ZQAOFGf8,654 +werkzeug/wrappers/__pycache__/__init__.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/accept.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/auth.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/base_request.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/base_response.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/common_descriptors.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/cors.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/etag.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/json.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/request.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/response.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/user_agent.cpython-38.pyc,, +werkzeug/wrappers/accept.py,sha256=_oZtAQkahvsrPRkNj2fieg7_St9P0NFC3SgZbJKS6xU,429 +werkzeug/wrappers/auth.py,sha256=rZPCzGxHk9R55PRkmS90kRywUVjjuMWzCGtH68qCq8U,856 +werkzeug/wrappers/base_request.py,sha256=saz9RyNQkvI_XLPYVm29KijNHmD1YzgxDqa0qHTbgss,1174 +werkzeug/wrappers/base_response.py,sha256=q_-TaYywT5G4zA-DWDRDJhJSat2_4O7gOPob6ye4_9A,1186 +werkzeug/wrappers/common_descriptors.py,sha256=v_kWLH3mvCiSRVJ1FNw7nO3w2UJfzY57UKKB5J4zCvE,898 +werkzeug/wrappers/cors.py,sha256=c5UndlZsZvYkbPrp6Gj5iSXxw_VOJDJHskO6-jRmNyQ,846 +werkzeug/wrappers/etag.py,sha256=XHWQQs7Mdd1oWezgBIsl-bYe8ydKkRZVil2Qd01D0Mo,846 +werkzeug/wrappers/json.py,sha256=HM1btPseGeXca0vnwQN_MvZl6h-qNsFY5YBKXKXFwus,410 +werkzeug/wrappers/request.py,sha256=0zAkCUwJbUBzioGy2UKxE6XpuXPAZbEhhML4WErzeBo,24818 +werkzeug/wrappers/response.py,sha256=95hXIysZTeNC0bqhvGB2fLBRKxedR_cgI5szZZWfyzw,35177 +werkzeug/wrappers/user_agent.py,sha256=Wl1-A0-1r8o7cHIZQTB55O4Ged6LpCKENaQDlOY5pXA,435 +werkzeug/wsgi.py,sha256=7psV3SHLtCzk1KSuGmIK5uP2QTDXyfCCDclyqCmIUO4,33715 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/WHEEL new file mode 100644 index 000000000..385faab05 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/top_level.txt new file mode 100644 index 000000000..6fe8da849 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/Werkzeug-2.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/__pycache__/easy_install.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/__pycache__/easy_install.cpython-38.pyc new file mode 100644 index 000000000..79ed8e8b4 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/__pycache__/easy_install.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/__pycache__/six.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/__pycache__/six.cpython-38.pyc new file mode 100644 index 000000000..35e58e1b0 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/__pycache__/six.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/INSTALLER b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/LICENSE b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/LICENSE new file mode 100644 index 000000000..40b077445 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2021, Brandon Nielsen +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/METADATA b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/METADATA new file mode 100644 index 000000000..cb5b25de2 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/METADATA @@ -0,0 +1,513 @@ +Metadata-Version: 2.1 +Name: aniso8601 +Version: 9.0.1 +Summary: A library for parsing ISO 8601 strings. +Home-page: https://bitbucket.org/nielsenb/aniso8601 +Author: Brandon Nielsen +Author-email: nielsenb@jetfuse.net +License: UNKNOWN +Project-URL: Documentation, https://aniso8601.readthedocs.io/ +Project-URL: Source, https://bitbucket.org/nielsenb/aniso8601 +Project-URL: Tracker, https://bitbucket.org/nielsenb/aniso8601/issues +Keywords: iso8601 parser +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +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: Topic :: Software Development :: Libraries :: Python Modules +Description-Content-Type: text/x-rst +Provides-Extra: dev +Requires-Dist: black ; extra == 'dev' +Requires-Dist: coverage ; extra == 'dev' +Requires-Dist: isort ; extra == 'dev' +Requires-Dist: pre-commit ; extra == 'dev' +Requires-Dist: pyenchant ; extra == 'dev' +Requires-Dist: pylint ; extra == 'dev' + +aniso8601 +========= + +Another ISO 8601 parser for Python +---------------------------------- + +Features +======== +* Pure Python implementation +* Logical behavior + + - Parse a time, get a `datetime.time `_ + - Parse a date, get a `datetime.date `_ + - Parse a datetime, get a `datetime.datetime `_ + - Parse a duration, get a `datetime.timedelta `_ + - Parse an interval, get a tuple of dates or datetimes + - Parse a repeating interval, get a date or datetime `generator `_ + +* UTC offset represented as fixed-offset tzinfo +* Parser separate from representation, allowing parsing to different datetime representations (see `Builders`_) +* No regular expressions + +Installation +============ + +The recommended installation method is to use pip:: + + $ pip install aniso8601 + +Alternatively, you can download the source (git repository hosted at `Bitbucket `_) and install directly:: + + $ python setup.py install + +Use +=== + +Parsing datetimes +----------------- + +*Consider* `datetime.datetime.fromisoformat `_ *for basic ISO 8601 datetime parsing* + +To parse a typical ISO 8601 datetime string:: + + >>> import aniso8601 + >>> aniso8601.parse_datetime('1977-06-10T12:00:00Z') + datetime.datetime(1977, 6, 10, 12, 0, tzinfo=+0:00:00 UTC) + +Alternative delimiters can be specified, for example, a space:: + + >>> aniso8601.parse_datetime('1977-06-10 12:00:00Z', delimiter=' ') + datetime.datetime(1977, 6, 10, 12, 0, tzinfo=+0:00:00 UTC) + +UTC offsets are supported:: + + >>> aniso8601.parse_datetime('1979-06-05T08:00:00-08:00') + datetime.datetime(1979, 6, 5, 8, 0, tzinfo=-8:00:00 UTC) + +If a UTC offset is not specified, the returned datetime will be naive:: + + >>> aniso8601.parse_datetime('1983-01-22T08:00:00') + datetime.datetime(1983, 1, 22, 8, 0) + +Leap seconds are currently not supported and attempting to parse one raises a :code:`LeapSecondError`:: + + >>> aniso8601.parse_datetime('2018-03-06T23:59:60') + Traceback (most recent call last): + File "", line 1, in + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/time.py", line 196, in parse_datetime + return builder.build_datetime(datepart, timepart) + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 237, in build_datetime + cls._build_object(time)) + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/__init__.py", line 336, in _build_object + return cls.build_time(hh=parsetuple.hh, mm=parsetuple.mm, + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 191, in build_time + hh, mm, ss, tz = cls.range_check_time(hh, mm, ss, tz) + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/__init__.py", line 266, in range_check_time + raise LeapSecondError('Leap seconds are not supported.') + aniso8601.exceptions.LeapSecondError: Leap seconds are not supported. + +To get the resolution of an ISO 8601 datetime string:: + + >>> aniso8601.get_datetime_resolution('1977-06-10T12:00:00Z') == aniso8601.resolution.TimeResolution.Seconds + True + >>> aniso8601.get_datetime_resolution('1977-06-10T12:00') == aniso8601.resolution.TimeResolution.Minutes + True + >>> aniso8601.get_datetime_resolution('1977-06-10T12') == aniso8601.resolution.TimeResolution.Hours + True + +Note that datetime resolutions map to :code:`TimeResolution` as a valid datetime must have at least one time member so the resolution mapping is equivalent. + +Parsing dates +------------- + +*Consider* `datetime.date.fromisoformat `_ *for basic ISO 8601 date parsing* + +To parse a date represented in an ISO 8601 string:: + + >>> import aniso8601 + >>> aniso8601.parse_date('1984-04-23') + datetime.date(1984, 4, 23) + +Basic format is supported as well:: + + >>> aniso8601.parse_date('19840423') + datetime.date(1984, 4, 23) + +To parse a date using the ISO 8601 week date format:: + + >>> aniso8601.parse_date('1986-W38-1') + datetime.date(1986, 9, 15) + +To parse an ISO 8601 ordinal date:: + + >>> aniso8601.parse_date('1988-132') + datetime.date(1988, 5, 11) + +To get the resolution of an ISO 8601 date string:: + + >>> aniso8601.get_date_resolution('1981-04-05') == aniso8601.resolution.DateResolution.Day + True + >>> aniso8601.get_date_resolution('1981-04') == aniso8601.resolution.DateResolution.Month + True + >>> aniso8601.get_date_resolution('1981') == aniso8601.resolution.DateResolution.Year + True + +Parsing times +------------- + +*Consider* `datetime.time.fromisoformat `_ *for basic ISO 8601 time parsing* + +To parse a time formatted as an ISO 8601 string:: + + >>> import aniso8601 + >>> aniso8601.parse_time('11:31:14') + datetime.time(11, 31, 14) + +As with all of the above, basic format is supported:: + + >>> aniso8601.parse_time('113114') + datetime.time(11, 31, 14) + +A UTC offset can be specified for times:: + + >>> aniso8601.parse_time('17:18:19-02:30') + datetime.time(17, 18, 19, tzinfo=-2:30:00 UTC) + >>> aniso8601.parse_time('171819Z') + datetime.time(17, 18, 19, tzinfo=+0:00:00 UTC) + +Reduced accuracy is supported:: + + >>> aniso8601.parse_time('21:42') + datetime.time(21, 42) + >>> aniso8601.parse_time('22') + datetime.time(22, 0) + +A decimal fraction is always allowed on the lowest order element of an ISO 8601 formatted time:: + + >>> aniso8601.parse_time('22:33.5') + datetime.time(22, 33, 30) + >>> aniso8601.parse_time('23.75') + datetime.time(23, 45) + +The decimal fraction can be specified with a comma instead of a full-stop:: + + >>> aniso8601.parse_time('22:33,5') + datetime.time(22, 33, 30) + >>> aniso8601.parse_time('23,75') + datetime.time(23, 45) + +Leap seconds are currently not supported and attempting to parse one raises a :code:`LeapSecondError`:: + + >>> aniso8601.parse_time('23:59:60') + Traceback (most recent call last): + File "", line 1, in + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/time.py", line 174, in parse_time + return builder.build_time(hh=hourstr, mm=minutestr, ss=secondstr, tz=tz) + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 191, in build_time + hh, mm, ss, tz = cls.range_check_time(hh, mm, ss, tz) + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/__init__.py", line 266, in range_check_time + raise LeapSecondError('Leap seconds are not supported.') + aniso8601.exceptions.LeapSecondError: Leap seconds are not supported. + +To get the resolution of an ISO 8601 time string:: + + >>> aniso8601.get_time_resolution('11:31:14') == aniso8601.resolution.TimeResolution.Seconds + True + >>> aniso8601.get_time_resolution('11:31') == aniso8601.resolution.TimeResolution.Minutes + True + >>> aniso8601.get_time_resolution('11') == aniso8601.resolution.TimeResolution.Hours + True + +Parsing durations +----------------- + +To parse a duration formatted as an ISO 8601 string:: + + >>> import aniso8601 + >>> aniso8601.parse_duration('P1Y2M3DT4H54M6S') + datetime.timedelta(428, 17646) + +Reduced accuracy is supported:: + + >>> aniso8601.parse_duration('P1Y') + datetime.timedelta(365) + +A decimal fraction is allowed on the lowest order element:: + + >>> aniso8601.parse_duration('P1YT3.5M') + datetime.timedelta(365, 210) + +The decimal fraction can be specified with a comma instead of a full-stop:: + + >>> aniso8601.parse_duration('P1YT3,5M') + datetime.timedelta(365, 210) + +Parsing a duration from a combined date and time is supported as well:: + + >>> aniso8601.parse_duration('P0001-01-02T01:30:05') + datetime.timedelta(397, 5405) + +To get the resolution of an ISO 8601 duration string:: + + >>> aniso8601.get_duration_resolution('P1Y2M3DT4H54M6S') == aniso8601.resolution.DurationResolution.Seconds + True + >>> aniso8601.get_duration_resolution('P1Y2M3DT4H54M') == aniso8601.resolution.DurationResolution.Minutes + True + >>> aniso8601.get_duration_resolution('P1Y2M3DT4H') == aniso8601.resolution.DurationResolution.Hours + True + >>> aniso8601.get_duration_resolution('P1Y2M3D') == aniso8601.resolution.DurationResolution.Days + True + >>> aniso8601.get_duration_resolution('P1Y2M') == aniso8601.resolution.DurationResolution.Months + True + >>> aniso8601.get_duration_resolution('P1Y') == aniso8601.resolution.DurationResolution.Years + True + +The default :code:`PythonTimeBuilder` assumes years are 365 days, and months are 30 days. Where calendar level accuracy is required, a `RelativeTimeBuilder `_ can be used, see also `Builders`_. + +Parsing intervals +----------------- + +To parse an interval specified by a start and end:: + + >>> import aniso8601 + >>> aniso8601.parse_interval('2007-03-01T13:00:00/2008-05-11T15:30:00') + (datetime.datetime(2007, 3, 1, 13, 0), datetime.datetime(2008, 5, 11, 15, 30)) + +Intervals specified by a start time and a duration are supported:: + + >>> aniso8601.parse_interval('2007-03-01T13:00:00Z/P1Y2M10DT2H30M') + (datetime.datetime(2007, 3, 1, 13, 0, tzinfo=+0:00:00 UTC), datetime.datetime(2008, 5, 9, 15, 30, tzinfo=+0:00:00 UTC)) + +A duration can also be specified by a duration and end time:: + + >>> aniso8601.parse_interval('P1M/1981-04-05') + (datetime.date(1981, 4, 5), datetime.date(1981, 3, 6)) + +Notice that the result of the above parse is not in order from earliest to latest. If sorted intervals are required, simply use the :code:`sorted` keyword as shown below:: + + >>> sorted(aniso8601.parse_interval('P1M/1981-04-05')) + [datetime.date(1981, 3, 6), datetime.date(1981, 4, 5)] + +The end of an interval is returned as a datetime when required to maintain the resolution specified by a duration, even if the duration start is given as a date:: + + >>> aniso8601.parse_interval('2014-11-12/PT4H54M6.5S') + (datetime.date(2014, 11, 12), datetime.datetime(2014, 11, 12, 4, 54, 6, 500000)) + >>> aniso8601.parse_interval('2007-03-01/P1.5D') + (datetime.date(2007, 3, 1), datetime.datetime(2007, 3, 2, 12, 0)) + +Concise representations are supported:: + + >>> aniso8601.parse_interval('2020-01-01/02') + (datetime.date(2020, 1, 1), datetime.date(2020, 1, 2)) + >>> aniso8601.parse_interval('2007-12-14T13:30/15:30') + (datetime.datetime(2007, 12, 14, 13, 30), datetime.datetime(2007, 12, 14, 15, 30)) + >>> aniso8601.parse_interval('2008-02-15/03-14') + (datetime.date(2008, 2, 15), datetime.date(2008, 3, 14)) + >>> aniso8601.parse_interval('2007-11-13T09:00/15T17:00') + (datetime.datetime(2007, 11, 13, 9, 0), datetime.datetime(2007, 11, 15, 17, 0)) + +Repeating intervals are supported as well, and return a `generator `_:: + + >>> aniso8601.parse_repeating_interval('R3/1981-04-05/P1D') + + >>> list(aniso8601.parse_repeating_interval('R3/1981-04-05/P1D')) + [datetime.date(1981, 4, 5), datetime.date(1981, 4, 6), datetime.date(1981, 4, 7)] + +Repeating intervals are allowed to go in the reverse direction:: + + >>> list(aniso8601.parse_repeating_interval('R2/PT1H2M/1980-03-05T01:01:00')) + [datetime.datetime(1980, 3, 5, 1, 1), datetime.datetime(1980, 3, 4, 23, 59)] + +Unbounded intervals are also allowed (Python 2):: + + >>> result = aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00') + >>> result.next() + datetime.datetime(1980, 3, 5, 1, 1) + >>> result.next() + datetime.datetime(1980, 3, 4, 23, 59) + +or for Python 3:: + + >>> result = aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00') + >>> next(result) + datetime.datetime(1980, 3, 5, 1, 1) + >>> next(result) + datetime.datetime(1980, 3, 4, 23, 59) + +Note that you should never try to convert a generator produced by an unbounded interval to a list:: + + >>> list(aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00')) + Traceback (most recent call last): + File "", line 1, in + File "/home/nielsenb/Jetfuse/aniso8601/aniso8601/aniso8601/builders/python.py", line 560, in _date_generator_unbounded + currentdate += timedelta + OverflowError: date value out of range + +To get the resolution of an ISO 8601 interval string:: + + >>> aniso8601.get_interval_resolution('2007-03-01T13:00:00/2008-05-11T15:30:00') == aniso8601.resolution.IntervalResolution.Seconds + True + >>> aniso8601.get_interval_resolution('2007-03-01T13:00/2008-05-11T15:30') == aniso8601.resolution.IntervalResolution.Minutes + True + >>> aniso8601.get_interval_resolution('2007-03-01T13/2008-05-11T15') == aniso8601.resolution.IntervalResolution.Hours + True + >>> aniso8601.get_interval_resolution('2007-03-01/2008-05-11') == aniso8601.resolution.IntervalResolution.Day + True + >>> aniso8601.get_interval_resolution('2007-03/P1Y') == aniso8601.resolution.IntervalResolution.Month + True + >>> aniso8601.get_interval_resolution('2007/P1Y') == aniso8601.resolution.IntervalResolution.Year + True + +And for repeating ISO 8601 interval strings:: + + >>> aniso8601.get_repeating_interval_resolution('R3/1981-04-05/P1D') == aniso8601.resolution.IntervalResolution.Day + True + >>> aniso8601.get_repeating_interval_resolution('R/PT1H2M/1980-03-05T01:01:00') == aniso8601.resolution.IntervalResolution.Seconds + True + +Builders +======== + +Builders can be used to change the output format of a parse operation. All parse functions have a :code:`builder` keyword argument which accepts a builder class. + +Two builders are included. The :code:`PythonTimeBuilder` (the default) in the :code:`aniso8601.builders.python` module, and the :code:`TupleBuilder` which returns the parse result as a corresponding named tuple and is located in the :code:`aniso8601.builders` module. + +Information on writing a builder can be found in `BUILDERS `_. + +The following builders are available as separate projects: + +* `RelativeTimeBuilder `_ supports parsing to `datetutil relativedelta types `_ for calendar level accuracy +* `AttoTimeBuilder `_ supports parsing directly to `attotime attodatetime and attotimedelta types `_ which support sub-nanosecond precision +* `NumPyTimeBuilder `_ supports parsing directly to `NumPy datetime64 and timedelta64 types `_ + +TupleBuilder +------------ + +The :code:`TupleBuilder` returns parse results as `named tuples `_. It is located in the :code:`aniso8601.builders` module. + +Datetimes +^^^^^^^^^ + +Parsing a datetime returns a :code:`DatetimeTuple` containing :code:`Date` and :code:`Time` tuples . The date tuple contains the following parse components: :code:`YYYY`, :code:`MM`, :code:`DD`, :code:`Www`, :code:`D`, :code:`DDD`. The time tuple contains the following parse components :code:`hh`, :code:`mm`, :code:`ss`, :code:`tz`, where :code:`tz` itself is a tuple with the following components :code:`negative`, :code:`Z`, :code:`hh`, :code:`mm`, :code:`name` with :code:`negative` and :code:`Z` being booleans:: + + >>> import aniso8601 + >>> from aniso8601.builders import TupleBuilder + >>> aniso8601.parse_datetime('1977-06-10T12:00:00', builder=TupleBuilder) + Datetime(date=Date(YYYY='1977', MM='06', DD='10', Www=None, D=None, DDD=None), time=Time(hh='12', mm='00', ss='00', tz=None)) + >>> aniso8601.parse_datetime('1979-06-05T08:00:00-08:00', builder=TupleBuilder) + Datetime(date=Date(YYYY='1979', MM='06', DD='05', Www=None, D=None, DDD=None), time=Time(hh='08', mm='00', ss='00', tz=Timezone(negative=True, Z=None, hh='08', mm='00', name='-08:00'))) + +Dates +^^^^^ + +Parsing a date returns a :code:`DateTuple` containing the following parse components: :code:`YYYY`, :code:`MM`, :code:`DD`, :code:`Www`, :code:`D`, :code:`DDD`:: + + >>> import aniso8601 + >>> from aniso8601.builders import TupleBuilder + >>> aniso8601.parse_date('1984-04-23', builder=TupleBuilder) + Date(YYYY='1984', MM='04', DD='23', Www=None, D=None, DDD=None) + >>> aniso8601.parse_date('1986-W38-1', builder=TupleBuilder) + Date(YYYY='1986', MM=None, DD=None, Www='38', D='1', DDD=None) + >>> aniso8601.parse_date('1988-132', builder=TupleBuilder) + Date(YYYY='1988', MM=None, DD=None, Www=None, D=None, DDD='132') + +Times +^^^^^ + +Parsing a time returns a :code:`TimeTuple` containing following parse components: :code:`hh`, :code:`mm`, :code:`ss`, :code:`tz`, where :code:`tz` is a :code:`TimezoneTuple` with the following components :code:`negative`, :code:`Z`, :code:`hh`, :code:`mm`, :code:`name`, with :code:`negative` and :code:`Z` being booleans:: + + >>> import aniso8601 + >>> from aniso8601.builders import TupleBuilder + >>> aniso8601.parse_time('11:31:14', builder=TupleBuilder) + Time(hh='11', mm='31', ss='14', tz=None) + >>> aniso8601.parse_time('171819Z', builder=TupleBuilder) + Time(hh='17', mm='18', ss='19', tz=Timezone(negative=False, Z=True, hh=None, mm=None, name='Z')) + >>> aniso8601.parse_time('17:18:19-02:30', builder=TupleBuilder) + Time(hh='17', mm='18', ss='19', tz=Timezone(negative=True, Z=None, hh='02', mm='30', name='-02:30')) + +Durations +^^^^^^^^^ + +Parsing a duration returns a :code:`DurationTuple` containing the following parse components: :code:`PnY`, :code:`PnM`, :code:`PnW`, :code:`PnD`, :code:`TnH`, :code:`TnM`, :code:`TnS`:: + + >>> import aniso8601 + >>> from aniso8601.builders import TupleBuilder + >>> aniso8601.parse_duration('P1Y2M3DT4H54M6S', builder=TupleBuilder) + Duration(PnY='1', PnM='2', PnW=None, PnD='3', TnH='4', TnM='54', TnS='6') + >>> aniso8601.parse_duration('P7W', builder=TupleBuilder) + Duration(PnY=None, PnM=None, PnW='7', PnD=None, TnH=None, TnM=None, TnS=None) + +Intervals +^^^^^^^^^ + +Parsing an interval returns an :code:`IntervalTuple` containing the following parse components: :code:`start`, :code:`end`, :code:`duration`, :code:`start` and :code:`end` may both be datetime or date tuples, :code:`duration` is a duration tuple:: + + >>> import aniso8601 + >>> from aniso8601.builders import TupleBuilder + >>> aniso8601.parse_interval('2007-03-01T13:00:00/2008-05-11T15:30:00', builder=TupleBuilder) + Interval(start=Datetime(date=Date(YYYY='2007', MM='03', DD='01', Www=None, D=None, DDD=None), time=Time(hh='13', mm='00', ss='00', tz=None)), end=Datetime(date=Date(YYYY='2008', MM='05', DD='11', Www=None, D=None, DDD=None), time=Time(hh='15', mm='30', ss='00', tz=None)), duration=None) + >>> aniso8601.parse_interval('2007-03-01T13:00:00Z/P1Y2M10DT2H30M', builder=TupleBuilder) + Interval(start=Datetime(date=Date(YYYY='2007', MM='03', DD='01', Www=None, D=None, DDD=None), time=Time(hh='13', mm='00', ss='00', tz=Timezone(negative=False, Z=True, hh=None, mm=None, name='Z'))), end=None, duration=Duration(PnY='1', PnM='2', PnW=None, PnD='10', TnH='2', TnM='30', TnS=None)) + >>> aniso8601.parse_interval('P1M/1981-04-05', builder=TupleBuilder) + Interval(start=None, end=Date(YYYY='1981', MM='04', DD='05', Www=None, D=None, DDD=None), duration=Duration(PnY=None, PnM='1', PnW=None, PnD=None, TnH=None, TnM=None, TnS=None)) + +A repeating interval returns a :code:`RepeatingIntervalTuple` containing the following parse components: :code:`R`, :code:`Rnn`, :code:`interval`, where :code:`R` is a boolean, :code:`True` for an unbounded interval, :code:`False` otherwise.:: + + >>> aniso8601.parse_repeating_interval('R3/1981-04-05/P1D', builder=TupleBuilder) + RepeatingInterval(R=False, Rnn='3', interval=Interval(start=Date(YYYY='1981', MM='04', DD='05', Www=None, D=None, DDD=None), end=None, duration=Duration(PnY=None, PnM=None, PnW=None, PnD='1', TnH=None, TnM=None, TnS=None))) + >>> aniso8601.parse_repeating_interval('R/PT1H2M/1980-03-05T01:01:00', builder=TupleBuilder) + RepeatingInterval(R=True, Rnn=None, interval=Interval(start=None, end=Datetime(date=Date(YYYY='1980', MM='03', DD='05', Www=None, D=None, DDD=None), time=Time(hh='01', mm='01', ss='00', tz=None)), duration=Duration(PnY=None, PnM=None, PnW=None, PnD=None, TnH='1', TnM='2', TnS=None))) + +Development +=========== + +Setup +----- + +It is recommended to develop using a `virtualenv `_. + +Inside a virtualenv, development dependencies can be installed automatically:: + + $ pip install -e .[dev] + +`pre-commit `_ is used for managing pre-commit hooks:: + + $ pre-commit install + +To run the pre-commit hooks manually:: + + $ pre-commit run --all-files + +Tests +----- + +Tests can be run using the `unittest testing framework `_:: + + $ python -m unittest discover aniso8601 + +Contributing +============ + +aniso8601 is an open source project hosted on `Bitbucket `_. + +Any and all bugs are welcome on our `issue tracker `_. +Of particular interest are valid ISO 8601 strings that don't parse, or invalid ones that do. At a minimum, +bug reports should include an example of the misbehaving string, as well as the expected result. Of course +patches containing unit tests (or fixed bugs) are welcome! + +References +========== + +* `ISO 8601:2004(E) `_ (Caution, PDF link) +* `Wikipedia article on ISO 8601 `_ +* `Discussion on alternative ISO 8601 parsers for Python `_ + + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/RECORD b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/RECORD new file mode 100644 index 000000000..8d4124b63 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/RECORD @@ -0,0 +1,60 @@ +aniso8601-9.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +aniso8601-9.0.1.dist-info/LICENSE,sha256=Z_-MGC_A4Nc1cViNi8B5tOSmJKknTE4mqSPeIxDTvSk,1501 +aniso8601-9.0.1.dist-info/METADATA,sha256=8x7vpReMZppobPRH8Q564bwHL9XFsgCFR3TKrHhfkjE,23431 +aniso8601-9.0.1.dist-info/RECORD,, +aniso8601-9.0.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +aniso8601-9.0.1.dist-info/top_level.txt,sha256=MVQomyeED8nGIH7PUQdMzxgLppIB48oYHtcmL17ETB0,10 +aniso8601/__init__.py,sha256=tHN7Nq-3I79PLzKkBuWun_UKgolnDrn7ISO8s1HlMdo,704 +aniso8601/__pycache__/__init__.cpython-38.pyc,, +aniso8601/__pycache__/compat.cpython-38.pyc,, +aniso8601/__pycache__/date.cpython-38.pyc,, +aniso8601/__pycache__/decimalfraction.cpython-38.pyc,, +aniso8601/__pycache__/duration.cpython-38.pyc,, +aniso8601/__pycache__/exceptions.cpython-38.pyc,, +aniso8601/__pycache__/interval.cpython-38.pyc,, +aniso8601/__pycache__/resolution.cpython-38.pyc,, +aniso8601/__pycache__/time.cpython-38.pyc,, +aniso8601/__pycache__/timezone.cpython-38.pyc,, +aniso8601/__pycache__/utcoffset.cpython-38.pyc,, +aniso8601/builders/__init__.py,sha256=sJanTP5Lo0lRxpLa5VKVBS9u6ZP8R1VRgozx5uSUMUU,17958 +aniso8601/builders/__pycache__/__init__.cpython-38.pyc,, +aniso8601/builders/__pycache__/python.cpython-38.pyc,, +aniso8601/builders/python.py,sha256=I0RhPY2syncaMwYRVJxM6ct-O_5MHnNFY3dcF6wvy0Y,22122 +aniso8601/builders/tests/__init__.py,sha256=XWM00Wzg9EZkSKyy3IW18Z8TiXfCbJS-XJNFVuylvuU,209 +aniso8601/builders/tests/__pycache__/__init__.cpython-38.pyc,, +aniso8601/builders/tests/__pycache__/test_init.cpython-38.pyc,, +aniso8601/builders/tests/__pycache__/test_python.cpython-38.pyc,, +aniso8601/builders/tests/test_init.py,sha256=wnDhjyb5iBt9l_zTXT96uqXus-igSqn5Kn_rqX_NSHA,29997 +aniso8601/builders/tests/test_python.py,sha256=pNr3lwfBKVSUQKc5BPmwCiCTpP_063WpOM-canDz4J8,61593 +aniso8601/compat.py,sha256=2exJsHW2DAxt_D2_mGj5mv0HCSMFeAAkPyFAM-ZFrA0,571 +aniso8601/date.py,sha256=IDn_kqeZshllwr4pICUNZhjbqSVVlYTyHmBOgp2MlNE,4475 +aniso8601/decimalfraction.py,sha256=EtwqSZJTtsQlu05m2guolhii5N1yN4dVv0v1zCZhiyk,333 +aniso8601/duration.py,sha256=6AAl9A-WM2Io898peIz9xbwOvxcLc6WYGUdkYuQlTU8,9583 +aniso8601/exceptions.py,sha256=-zrdcKocZhzhl71HhgVKXWF481XDWO3UhinbcycCzPU,1313 +aniso8601/interval.py,sha256=7e5wICHdF2gTeFluPxBrzaA4-_5b78QzXC62DSnNzlM,10763 +aniso8601/resolution.py,sha256=ee7GxL865D0dJL70TsXScz4Kzo_dwMORNvfuyCXdsgI,684 +aniso8601/tests/__init__.py,sha256=XWM00Wzg9EZkSKyy3IW18Z8TiXfCbJS-XJNFVuylvuU,209 +aniso8601/tests/__pycache__/__init__.cpython-38.pyc,, +aniso8601/tests/__pycache__/compat.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_compat.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_date.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_decimalfraction.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_duration.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_init.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_interval.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_time.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_timezone.cpython-38.pyc,, +aniso8601/tests/__pycache__/test_utcoffset.cpython-38.pyc,, +aniso8601/tests/compat.py,sha256=9HJqKvl0PIFBjePUgT-1eMGkA9tlESX0wNDkPvV7GOk,346 +aniso8601/tests/test_compat.py,sha256=2oFOFLKTfOJIMbLjkeVhrkxSDMjE0wM-NB86SJ6st5g,763 +aniso8601/tests/test_date.py,sha256=3AWmIHTS2sxm9_ZUYcI2w9ALJOYnHkkYEwlD1VW90iQ,8960 +aniso8601/tests/test_decimalfraction.py,sha256=T4R_SY24DW30YuQkyofxvAmngTuXtsmwd77pF25QAlc,578 +aniso8601/tests/test_duration.py,sha256=ZqUxodLrDBZ1GZWutFXjktAFHYS1hidxLclIGZP7aSA,44952 +aniso8601/tests/test_init.py,sha256=GazCeGTv-OFocCx9Cck04b-c1cWiiRnqhGwoGgm4Y1Q,1689 +aniso8601/tests/test_interval.py,sha256=lTg-E1vW1xmgwiWfHHwJDJ25AogSR-1p-0L4O2gQKQw,60457 +aniso8601/tests/test_time.py,sha256=HLutGVdg2_HHU51U2eEEZ9UNwljrQBPU_PtX8JrdVV0,19147 +aniso8601/tests/test_timezone.py,sha256=Shw7-fcUJZAbH7diCx37iXZ4VZEH45lqIgMJvoQQhtQ,4649 +aniso8601/tests/test_utcoffset.py,sha256=fRNuiz3WPMrHtrdMGK3HOuZRYd68hR-VNldbwVG-cDA,1926 +aniso8601/time.py,sha256=9IRsCERfEl_SnBBUIOR8E43XFD7Y2EqhowjiCcfinb0,5688 +aniso8601/timezone.py,sha256=5_LRd_pYd08i2hmXsn_1tTUxKOI4caSvxci-VByHCWU,2134 +aniso8601/utcoffset.py,sha256=8Gh8WNk_q9ELLEFZLMPbMESH-yqcoNFjul7VcpHq_1Q,2423 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/WHEEL b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/WHEEL new file mode 100644 index 000000000..01b8fc7d4 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/top_level.txt b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/top_level.txt new file mode 100644 index 000000000..166ae78c5 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601-9.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +aniso8601 diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__init__.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__init__.py new file mode 100644 index 000000000..033d30b9d --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +from aniso8601.date import get_date_resolution, parse_date +from aniso8601.duration import get_duration_resolution, parse_duration +from aniso8601.interval import ( + get_interval_resolution, + get_repeating_interval_resolution, + parse_interval, + parse_repeating_interval, +) + +# Import the main parsing functions so they are readily available +from aniso8601.time import ( + get_datetime_resolution, + get_time_resolution, + parse_datetime, + parse_time, +) + +__version__ = "9.0.1" diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/__init__.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 000000000..35c7dcf92 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/__init__.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/compat.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/compat.cpython-38.pyc new file mode 100644 index 000000000..64ff14664 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/compat.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/date.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/date.cpython-38.pyc new file mode 100644 index 000000000..349d163e3 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/date.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/decimalfraction.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/decimalfraction.cpython-38.pyc new file mode 100644 index 000000000..ac17174c6 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/decimalfraction.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/duration.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/duration.cpython-38.pyc new file mode 100644 index 000000000..61efc4436 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/duration.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/exceptions.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/exceptions.cpython-38.pyc new file mode 100644 index 000000000..3c1cd2f01 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/exceptions.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/interval.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/interval.cpython-38.pyc new file mode 100644 index 000000000..889c325c8 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/interval.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/resolution.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/resolution.cpython-38.pyc new file mode 100644 index 000000000..8ac253259 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/resolution.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/time.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/time.cpython-38.pyc new file mode 100644 index 000000000..9461e71bb Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/time.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/timezone.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/timezone.cpython-38.pyc new file mode 100644 index 000000000..f683ef487 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/timezone.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/utcoffset.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/utcoffset.cpython-38.pyc new file mode 100644 index 000000000..7e39345c9 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/__pycache__/utcoffset.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__init__.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__init__.py new file mode 100644 index 000000000..834c72a6b --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__init__.py @@ -0,0 +1,614 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +import calendar +from collections import namedtuple + +from aniso8601.exceptions import ( + DayOutOfBoundsError, + HoursOutOfBoundsError, + ISOFormatError, + LeapSecondError, + MidnightBoundsError, + MinutesOutOfBoundsError, + MonthOutOfBoundsError, + SecondsOutOfBoundsError, + WeekOutOfBoundsError, + YearOutOfBoundsError, +) + +DateTuple = namedtuple("Date", ["YYYY", "MM", "DD", "Www", "D", "DDD"]) +TimeTuple = namedtuple("Time", ["hh", "mm", "ss", "tz"]) +DatetimeTuple = namedtuple("Datetime", ["date", "time"]) +DurationTuple = namedtuple( + "Duration", ["PnY", "PnM", "PnW", "PnD", "TnH", "TnM", "TnS"] +) +IntervalTuple = namedtuple("Interval", ["start", "end", "duration"]) +RepeatingIntervalTuple = namedtuple("RepeatingInterval", ["R", "Rnn", "interval"]) +TimezoneTuple = namedtuple("Timezone", ["negative", "Z", "hh", "mm", "name"]) + +Limit = namedtuple( + "Limit", + [ + "casterrorstring", + "min", + "max", + "rangeexception", + "rangeerrorstring", + "rangefunc", + ], +) + + +def cast( + value, + castfunction, + caughtexceptions=(ValueError,), + thrownexception=ISOFormatError, + thrownmessage=None, +): + try: + result = castfunction(value) + except caughtexceptions: + raise thrownexception(thrownmessage) + + return result + + +def range_check(valuestr, limit): + # Returns cast value if in range, raises defined exceptions on failure + if valuestr is None: + return None + + if "." in valuestr: + castfunc = float + else: + castfunc = int + + value = cast(valuestr, castfunc, thrownmessage=limit.casterrorstring) + + if limit.min is not None and value < limit.min: + raise limit.rangeexception(limit.rangeerrorstring) + + if limit.max is not None and value > limit.max: + raise limit.rangeexception(limit.rangeerrorstring) + + return value + + +class BaseTimeBuilder(object): + # Limit tuple format cast function, cast error string, + # lower limit, upper limit, limit error string + DATE_YYYY_LIMIT = Limit( + "Invalid year string.", + 0000, + 9999, + YearOutOfBoundsError, + "Year must be between 1..9999.", + range_check, + ) + DATE_MM_LIMIT = Limit( + "Invalid month string.", + 1, + 12, + MonthOutOfBoundsError, + "Month must be between 1..12.", + range_check, + ) + DATE_DD_LIMIT = Limit( + "Invalid day string.", + 1, + 31, + DayOutOfBoundsError, + "Day must be between 1..31.", + range_check, + ) + DATE_WWW_LIMIT = Limit( + "Invalid week string.", + 1, + 53, + WeekOutOfBoundsError, + "Week number must be between 1..53.", + range_check, + ) + DATE_D_LIMIT = Limit( + "Invalid weekday string.", + 1, + 7, + DayOutOfBoundsError, + "Weekday number must be between 1..7.", + range_check, + ) + DATE_DDD_LIMIT = Limit( + "Invalid ordinal day string.", + 1, + 366, + DayOutOfBoundsError, + "Ordinal day must be between 1..366.", + range_check, + ) + TIME_HH_LIMIT = Limit( + "Invalid hour string.", + 0, + 24, + HoursOutOfBoundsError, + "Hour must be between 0..24 with " "24 representing midnight.", + range_check, + ) + TIME_MM_LIMIT = Limit( + "Invalid minute string.", + 0, + 59, + MinutesOutOfBoundsError, + "Minute must be between 0..59.", + range_check, + ) + TIME_SS_LIMIT = Limit( + "Invalid second string.", + 0, + 60, + SecondsOutOfBoundsError, + "Second must be between 0..60 with " "60 representing a leap second.", + range_check, + ) + TZ_HH_LIMIT = Limit( + "Invalid timezone hour string.", + 0, + 23, + HoursOutOfBoundsError, + "Hour must be between 0..23.", + range_check, + ) + TZ_MM_LIMIT = Limit( + "Invalid timezone minute string.", + 0, + 59, + MinutesOutOfBoundsError, + "Minute must be between 0..59.", + range_check, + ) + DURATION_PNY_LIMIT = Limit( + "Invalid year duration string.", + 0, + None, + ISOFormatError, + "Duration years component must be positive.", + range_check, + ) + DURATION_PNM_LIMIT = Limit( + "Invalid month duration string.", + 0, + None, + ISOFormatError, + "Duration months component must be positive.", + range_check, + ) + DURATION_PNW_LIMIT = Limit( + "Invalid week duration string.", + 0, + None, + ISOFormatError, + "Duration weeks component must be positive.", + range_check, + ) + DURATION_PND_LIMIT = Limit( + "Invalid day duration string.", + 0, + None, + ISOFormatError, + "Duration days component must be positive.", + range_check, + ) + DURATION_TNH_LIMIT = Limit( + "Invalid hour duration string.", + 0, + None, + ISOFormatError, + "Duration hours component must be positive.", + range_check, + ) + DURATION_TNM_LIMIT = Limit( + "Invalid minute duration string.", + 0, + None, + ISOFormatError, + "Duration minutes component must be positive.", + range_check, + ) + DURATION_TNS_LIMIT = Limit( + "Invalid second duration string.", + 0, + None, + ISOFormatError, + "Duration seconds component must be positive.", + range_check, + ) + INTERVAL_RNN_LIMIT = Limit( + "Invalid duration repetition string.", + 0, + None, + ISOFormatError, + "Duration repetition count must be positive.", + range_check, + ) + + DATE_RANGE_DICT = { + "YYYY": DATE_YYYY_LIMIT, + "MM": DATE_MM_LIMIT, + "DD": DATE_DD_LIMIT, + "Www": DATE_WWW_LIMIT, + "D": DATE_D_LIMIT, + "DDD": DATE_DDD_LIMIT, + } + + TIME_RANGE_DICT = {"hh": TIME_HH_LIMIT, "mm": TIME_MM_LIMIT, "ss": TIME_SS_LIMIT} + + DURATION_RANGE_DICT = { + "PnY": DURATION_PNY_LIMIT, + "PnM": DURATION_PNM_LIMIT, + "PnW": DURATION_PNW_LIMIT, + "PnD": DURATION_PND_LIMIT, + "TnH": DURATION_TNH_LIMIT, + "TnM": DURATION_TNM_LIMIT, + "TnS": DURATION_TNS_LIMIT, + } + + REPEATING_INTERVAL_RANGE_DICT = {"Rnn": INTERVAL_RNN_LIMIT} + + TIMEZONE_RANGE_DICT = {"hh": TZ_HH_LIMIT, "mm": TZ_MM_LIMIT} + + LEAP_SECONDS_SUPPORTED = False + + @classmethod + def build_date(cls, YYYY=None, MM=None, DD=None, Www=None, D=None, DDD=None): + raise NotImplementedError + + @classmethod + def build_time(cls, hh=None, mm=None, ss=None, tz=None): + raise NotImplementedError + + @classmethod + def build_datetime(cls, date, time): + raise NotImplementedError + + @classmethod + def build_duration( + cls, PnY=None, PnM=None, PnW=None, PnD=None, TnH=None, TnM=None, TnS=None + ): + raise NotImplementedError + + @classmethod + def build_interval(cls, start=None, end=None, duration=None): + # start, end, and duration are all tuples + raise NotImplementedError + + @classmethod + def build_repeating_interval(cls, R=None, Rnn=None, interval=None): + # interval is a tuple + raise NotImplementedError + + @classmethod + def build_timezone(cls, negative=None, Z=None, hh=None, mm=None, name=""): + raise NotImplementedError + + @classmethod + def range_check_date( + cls, YYYY=None, MM=None, DD=None, Www=None, D=None, DDD=None, rangedict=None + ): + if rangedict is None: + rangedict = cls.DATE_RANGE_DICT + + if "YYYY" in rangedict: + YYYY = rangedict["YYYY"].rangefunc(YYYY, rangedict["YYYY"]) + + if "MM" in rangedict: + MM = rangedict["MM"].rangefunc(MM, rangedict["MM"]) + + if "DD" in rangedict: + DD = rangedict["DD"].rangefunc(DD, rangedict["DD"]) + + if "Www" in rangedict: + Www = rangedict["Www"].rangefunc(Www, rangedict["Www"]) + + if "D" in rangedict: + D = rangedict["D"].rangefunc(D, rangedict["D"]) + + if "DDD" in rangedict: + DDD = rangedict["DDD"].rangefunc(DDD, rangedict["DDD"]) + + if DD is not None: + # Check calendar + if DD > calendar.monthrange(YYYY, MM)[1]: + raise DayOutOfBoundsError( + "{0} is out of range for {1}-{2}".format(DD, YYYY, MM) + ) + + if DDD is not None: + if calendar.isleap(YYYY) is False and DDD == 366: + raise DayOutOfBoundsError( + "{0} is only valid for leap year.".format(DDD) + ) + + return (YYYY, MM, DD, Www, D, DDD) + + @classmethod + def range_check_time(cls, hh=None, mm=None, ss=None, tz=None, rangedict=None): + # Used for midnight and leap second handling + midnight = False # Handle hh = '24' specially + + if rangedict is None: + rangedict = cls.TIME_RANGE_DICT + + if "hh" in rangedict: + try: + hh = rangedict["hh"].rangefunc(hh, rangedict["hh"]) + except HoursOutOfBoundsError as e: + if float(hh) > 24 and float(hh) < 25: + raise MidnightBoundsError("Hour 24 may only represent midnight.") + + raise e + + if "mm" in rangedict: + mm = rangedict["mm"].rangefunc(mm, rangedict["mm"]) + + if "ss" in rangedict: + ss = rangedict["ss"].rangefunc(ss, rangedict["ss"]) + + if hh is not None and hh == 24: + midnight = True + + # Handle midnight range + if midnight is True and ( + (mm is not None and mm != 0) or (ss is not None and ss != 0) + ): + raise MidnightBoundsError("Hour 24 may only represent midnight.") + + if cls.LEAP_SECONDS_SUPPORTED is True: + if hh != 23 and mm != 59 and ss == 60: + raise cls.TIME_SS_LIMIT.rangeexception( + cls.TIME_SS_LIMIT.rangeerrorstring + ) + else: + if hh == 23 and mm == 59 and ss == 60: + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + raise LeapSecondError("Leap seconds are not supported.") + + if ss == 60: + raise cls.TIME_SS_LIMIT.rangeexception( + cls.TIME_SS_LIMIT.rangeerrorstring + ) + + return (hh, mm, ss, tz) + + @classmethod + def range_check_duration( + cls, + PnY=None, + PnM=None, + PnW=None, + PnD=None, + TnH=None, + TnM=None, + TnS=None, + rangedict=None, + ): + if rangedict is None: + rangedict = cls.DURATION_RANGE_DICT + + if "PnY" in rangedict: + PnY = rangedict["PnY"].rangefunc(PnY, rangedict["PnY"]) + + if "PnM" in rangedict: + PnM = rangedict["PnM"].rangefunc(PnM, rangedict["PnM"]) + + if "PnW" in rangedict: + PnW = rangedict["PnW"].rangefunc(PnW, rangedict["PnW"]) + + if "PnD" in rangedict: + PnD = rangedict["PnD"].rangefunc(PnD, rangedict["PnD"]) + + if "TnH" in rangedict: + TnH = rangedict["TnH"].rangefunc(TnH, rangedict["TnH"]) + + if "TnM" in rangedict: + TnM = rangedict["TnM"].rangefunc(TnM, rangedict["TnM"]) + + if "TnS" in rangedict: + TnS = rangedict["TnS"].rangefunc(TnS, rangedict["TnS"]) + + return (PnY, PnM, PnW, PnD, TnH, TnM, TnS) + + @classmethod + def range_check_repeating_interval( + cls, R=None, Rnn=None, interval=None, rangedict=None + ): + if rangedict is None: + rangedict = cls.REPEATING_INTERVAL_RANGE_DICT + + if "Rnn" in rangedict: + Rnn = rangedict["Rnn"].rangefunc(Rnn, rangedict["Rnn"]) + + return (R, Rnn, interval) + + @classmethod + def range_check_timezone( + cls, negative=None, Z=None, hh=None, mm=None, name="", rangedict=None + ): + if rangedict is None: + rangedict = cls.TIMEZONE_RANGE_DICT + + if "hh" in rangedict: + hh = rangedict["hh"].rangefunc(hh, rangedict["hh"]) + + if "mm" in rangedict: + mm = rangedict["mm"].rangefunc(mm, rangedict["mm"]) + + return (negative, Z, hh, mm, name) + + @classmethod + def _build_object(cls, parsetuple): + # Given a TupleBuilder tuple, build the correct object + if type(parsetuple) is DateTuple: + return cls.build_date( + YYYY=parsetuple.YYYY, + MM=parsetuple.MM, + DD=parsetuple.DD, + Www=parsetuple.Www, + D=parsetuple.D, + DDD=parsetuple.DDD, + ) + + if type(parsetuple) is TimeTuple: + return cls.build_time( + hh=parsetuple.hh, mm=parsetuple.mm, ss=parsetuple.ss, tz=parsetuple.tz + ) + + if type(parsetuple) is DatetimeTuple: + return cls.build_datetime(parsetuple.date, parsetuple.time) + + if type(parsetuple) is DurationTuple: + return cls.build_duration( + PnY=parsetuple.PnY, + PnM=parsetuple.PnM, + PnW=parsetuple.PnW, + PnD=parsetuple.PnD, + TnH=parsetuple.TnH, + TnM=parsetuple.TnM, + TnS=parsetuple.TnS, + ) + + if type(parsetuple) is IntervalTuple: + return cls.build_interval( + start=parsetuple.start, end=parsetuple.end, duration=parsetuple.duration + ) + + if type(parsetuple) is RepeatingIntervalTuple: + return cls.build_repeating_interval( + R=parsetuple.R, Rnn=parsetuple.Rnn, interval=parsetuple.interval + ) + + return cls.build_timezone( + negative=parsetuple.negative, + Z=parsetuple.Z, + hh=parsetuple.hh, + mm=parsetuple.mm, + name=parsetuple.name, + ) + + @classmethod + def _is_interval_end_concise(cls, endtuple): + if type(endtuple) is TimeTuple: + return True + + if type(endtuple) is DatetimeTuple: + enddatetuple = endtuple.date + else: + enddatetuple = endtuple + + if enddatetuple.YYYY is None: + return True + + return False + + @classmethod + def _combine_concise_interval_tuples(cls, starttuple, conciseendtuple): + starttimetuple = None + startdatetuple = None + + endtimetuple = None + enddatetuple = None + + if type(starttuple) is DateTuple: + startdatetuple = starttuple + else: + # Start is a datetime + starttimetuple = starttuple.time + startdatetuple = starttuple.date + + if type(conciseendtuple) is DateTuple: + enddatetuple = conciseendtuple + elif type(conciseendtuple) is DatetimeTuple: + enddatetuple = conciseendtuple.date + endtimetuple = conciseendtuple.time + else: + # Time + endtimetuple = conciseendtuple + + if enddatetuple is not None: + if enddatetuple.YYYY is None and enddatetuple.MM is None: + newenddatetuple = DateTuple( + YYYY=startdatetuple.YYYY, + MM=startdatetuple.MM, + DD=enddatetuple.DD, + Www=enddatetuple.Www, + D=enddatetuple.D, + DDD=enddatetuple.DDD, + ) + else: + newenddatetuple = DateTuple( + YYYY=startdatetuple.YYYY, + MM=enddatetuple.MM, + DD=enddatetuple.DD, + Www=enddatetuple.Www, + D=enddatetuple.D, + DDD=enddatetuple.DDD, + ) + + if (starttimetuple is not None and starttimetuple.tz is not None) and ( + endtimetuple is not None and endtimetuple.tz != starttimetuple.tz + ): + # Copy the timezone across + endtimetuple = TimeTuple( + hh=endtimetuple.hh, + mm=endtimetuple.mm, + ss=endtimetuple.ss, + tz=starttimetuple.tz, + ) + + if enddatetuple is not None and endtimetuple is None: + return newenddatetuple + + if enddatetuple is not None and endtimetuple is not None: + return TupleBuilder.build_datetime(newenddatetuple, endtimetuple) + + return TupleBuilder.build_datetime(startdatetuple, endtimetuple) + + +class TupleBuilder(BaseTimeBuilder): + # Builder used to return the arguments as a tuple, cleans up some parse methods + @classmethod + def build_date(cls, YYYY=None, MM=None, DD=None, Www=None, D=None, DDD=None): + + return DateTuple(YYYY, MM, DD, Www, D, DDD) + + @classmethod + def build_time(cls, hh=None, mm=None, ss=None, tz=None): + return TimeTuple(hh, mm, ss, tz) + + @classmethod + def build_datetime(cls, date, time): + return DatetimeTuple(date, time) + + @classmethod + def build_duration( + cls, PnY=None, PnM=None, PnW=None, PnD=None, TnH=None, TnM=None, TnS=None + ): + + return DurationTuple(PnY, PnM, PnW, PnD, TnH, TnM, TnS) + + @classmethod + def build_interval(cls, start=None, end=None, duration=None): + return IntervalTuple(start, end, duration) + + @classmethod + def build_repeating_interval(cls, R=None, Rnn=None, interval=None): + return RepeatingIntervalTuple(R, Rnn, interval) + + @classmethod + def build_timezone(cls, negative=None, Z=None, hh=None, mm=None, name=""): + return TimezoneTuple(negative, Z, hh, mm, name) diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__pycache__/__init__.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 000000000..f3ed3d14a Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__pycache__/__init__.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__pycache__/python.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__pycache__/python.cpython-38.pyc new file mode 100644 index 000000000..7da975d36 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/__pycache__/python.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/python.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/python.py new file mode 100644 index 000000000..8956740e7 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/python.py @@ -0,0 +1,705 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +import datetime +from collections import namedtuple +from functools import partial + +from aniso8601.builders import ( + BaseTimeBuilder, + DatetimeTuple, + DateTuple, + Limit, + TimeTuple, + TupleBuilder, + cast, + range_check, +) +from aniso8601.exceptions import ( + DayOutOfBoundsError, + HoursOutOfBoundsError, + ISOFormatError, + LeapSecondError, + MidnightBoundsError, + MinutesOutOfBoundsError, + MonthOutOfBoundsError, + SecondsOutOfBoundsError, + WeekOutOfBoundsError, + YearOutOfBoundsError, +) +from aniso8601.utcoffset import UTCOffset + +DAYS_PER_YEAR = 365 +DAYS_PER_MONTH = 30 +DAYS_PER_WEEK = 7 + +HOURS_PER_DAY = 24 + +MINUTES_PER_HOUR = 60 +MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY + +SECONDS_PER_MINUTE = 60 +SECONDS_PER_DAY = MINUTES_PER_DAY * SECONDS_PER_MINUTE + +MICROSECONDS_PER_SECOND = int(1e6) + +MICROSECONDS_PER_MINUTE = 60 * MICROSECONDS_PER_SECOND +MICROSECONDS_PER_HOUR = 60 * MICROSECONDS_PER_MINUTE +MICROSECONDS_PER_DAY = 24 * MICROSECONDS_PER_HOUR +MICROSECONDS_PER_WEEK = 7 * MICROSECONDS_PER_DAY +MICROSECONDS_PER_MONTH = DAYS_PER_MONTH * MICROSECONDS_PER_DAY +MICROSECONDS_PER_YEAR = DAYS_PER_YEAR * MICROSECONDS_PER_DAY + +TIMEDELTA_MAX_DAYS = datetime.timedelta.max.days + +FractionalComponent = namedtuple( + "FractionalComponent", ["principal", "microsecondremainder"] +) + + +def year_range_check(valuestr, limit): + YYYYstr = valuestr + + # Truncated dates, like '19', refer to 1900-1999 inclusive, + # we simply parse to 1900 + if len(valuestr) < 4: + # Shift 0s in from the left to form complete year + YYYYstr = valuestr.ljust(4, "0") + + return range_check(YYYYstr, limit) + + +def fractional_range_check(conversion, valuestr, limit): + if valuestr is None: + return None + + if "." in valuestr: + castfunc = partial(_cast_to_fractional_component, conversion) + else: + castfunc = int + + value = cast(valuestr, castfunc, thrownmessage=limit.casterrorstring) + + if type(value) is FractionalComponent: + tocheck = float(valuestr) + else: + tocheck = int(valuestr) + + if limit.min is not None and tocheck < limit.min: + raise limit.rangeexception(limit.rangeerrorstring) + + if limit.max is not None and tocheck > limit.max: + raise limit.rangeexception(limit.rangeerrorstring) + + return value + + +def _cast_to_fractional_component(conversion, floatstr): + # Splits a string with a decimal point into an int, and + # int representing the floating point remainder as a number + # of microseconds, determined by multiplying by conversion + intpart, floatpart = floatstr.split(".") + + intvalue = int(intpart) + preconvertedvalue = int(floatpart) + + convertedvalue = (preconvertedvalue * conversion) // (10 ** len(floatpart)) + + return FractionalComponent(intvalue, convertedvalue) + + +class PythonTimeBuilder(BaseTimeBuilder): + # 0000 (1 BC) is not representable as a Python date + DATE_YYYY_LIMIT = Limit( + "Invalid year string.", + datetime.MINYEAR, + datetime.MAXYEAR, + YearOutOfBoundsError, + "Year must be between {0}..{1}.".format(datetime.MINYEAR, datetime.MAXYEAR), + year_range_check, + ) + TIME_HH_LIMIT = Limit( + "Invalid hour string.", + 0, + 24, + HoursOutOfBoundsError, + "Hour must be between 0..24 with " "24 representing midnight.", + partial(fractional_range_check, MICROSECONDS_PER_HOUR), + ) + TIME_MM_LIMIT = Limit( + "Invalid minute string.", + 0, + 59, + MinutesOutOfBoundsError, + "Minute must be between 0..59.", + partial(fractional_range_check, MICROSECONDS_PER_MINUTE), + ) + TIME_SS_LIMIT = Limit( + "Invalid second string.", + 0, + 60, + SecondsOutOfBoundsError, + "Second must be between 0..60 with " "60 representing a leap second.", + partial(fractional_range_check, MICROSECONDS_PER_SECOND), + ) + DURATION_PNY_LIMIT = Limit( + "Invalid year duration string.", + None, + None, + YearOutOfBoundsError, + None, + partial(fractional_range_check, MICROSECONDS_PER_YEAR), + ) + DURATION_PNM_LIMIT = Limit( + "Invalid month duration string.", + None, + None, + MonthOutOfBoundsError, + None, + partial(fractional_range_check, MICROSECONDS_PER_MONTH), + ) + DURATION_PNW_LIMIT = Limit( + "Invalid week duration string.", + None, + None, + WeekOutOfBoundsError, + None, + partial(fractional_range_check, MICROSECONDS_PER_WEEK), + ) + DURATION_PND_LIMIT = Limit( + "Invalid day duration string.", + None, + None, + DayOutOfBoundsError, + None, + partial(fractional_range_check, MICROSECONDS_PER_DAY), + ) + DURATION_TNH_LIMIT = Limit( + "Invalid hour duration string.", + None, + None, + HoursOutOfBoundsError, + None, + partial(fractional_range_check, MICROSECONDS_PER_HOUR), + ) + DURATION_TNM_LIMIT = Limit( + "Invalid minute duration string.", + None, + None, + MinutesOutOfBoundsError, + None, + partial(fractional_range_check, MICROSECONDS_PER_MINUTE), + ) + DURATION_TNS_LIMIT = Limit( + "Invalid second duration string.", + None, + None, + SecondsOutOfBoundsError, + None, + partial(fractional_range_check, MICROSECONDS_PER_SECOND), + ) + + DATE_RANGE_DICT = BaseTimeBuilder.DATE_RANGE_DICT + DATE_RANGE_DICT["YYYY"] = DATE_YYYY_LIMIT + + TIME_RANGE_DICT = {"hh": TIME_HH_LIMIT, "mm": TIME_MM_LIMIT, "ss": TIME_SS_LIMIT} + + DURATION_RANGE_DICT = { + "PnY": DURATION_PNY_LIMIT, + "PnM": DURATION_PNM_LIMIT, + "PnW": DURATION_PNW_LIMIT, + "PnD": DURATION_PND_LIMIT, + "TnH": DURATION_TNH_LIMIT, + "TnM": DURATION_TNM_LIMIT, + "TnS": DURATION_TNS_LIMIT, + } + + @classmethod + def build_date(cls, YYYY=None, MM=None, DD=None, Www=None, D=None, DDD=None): + YYYY, MM, DD, Www, D, DDD = cls.range_check_date(YYYY, MM, DD, Www, D, DDD) + + if MM is None: + MM = 1 + + if DD is None: + DD = 1 + + if DDD is not None: + return PythonTimeBuilder._build_ordinal_date(YYYY, DDD) + + if Www is not None: + return PythonTimeBuilder._build_week_date(YYYY, Www, isoday=D) + + return datetime.date(YYYY, MM, DD) + + @classmethod + def build_time(cls, hh=None, mm=None, ss=None, tz=None): + # Builds a time from the given parts, handling fractional arguments + # where necessary + hours = 0 + minutes = 0 + seconds = 0 + microseconds = 0 + + hh, mm, ss, tz = cls.range_check_time(hh, mm, ss, tz) + + if type(hh) is FractionalComponent: + hours = hh.principal + microseconds = hh.microsecondremainder + elif hh is not None: + hours = hh + + if type(mm) is FractionalComponent: + minutes = mm.principal + microseconds = mm.microsecondremainder + elif mm is not None: + minutes = mm + + if type(ss) is FractionalComponent: + seconds = ss.principal + microseconds = ss.microsecondremainder + elif ss is not None: + seconds = ss + + ( + hours, + minutes, + seconds, + microseconds, + ) = PythonTimeBuilder._distribute_microseconds( + microseconds, + (hours, minutes, seconds), + (MICROSECONDS_PER_HOUR, MICROSECONDS_PER_MINUTE, MICROSECONDS_PER_SECOND), + ) + + # Move midnight into range + if hours == 24: + hours = 0 + + # Datetimes don't handle fractional components, so we use a timedelta + if tz is not None: + return ( + datetime.datetime( + 1, 1, 1, hour=hours, minute=minutes, tzinfo=cls._build_object(tz) + ) + + datetime.timedelta(seconds=seconds, microseconds=microseconds) + ).timetz() + + return ( + datetime.datetime(1, 1, 1, hour=hours, minute=minutes) + + datetime.timedelta(seconds=seconds, microseconds=microseconds) + ).time() + + @classmethod + def build_datetime(cls, date, time): + return datetime.datetime.combine( + cls._build_object(date), cls._build_object(time) + ) + + @classmethod + def build_duration( + cls, PnY=None, PnM=None, PnW=None, PnD=None, TnH=None, TnM=None, TnS=None + ): + # PnY and PnM will be distributed to PnD, microsecond remainder to TnS + PnY, PnM, PnW, PnD, TnH, TnM, TnS = cls.range_check_duration( + PnY, PnM, PnW, PnD, TnH, TnM, TnS + ) + + seconds = TnS.principal + microseconds = TnS.microsecondremainder + + return datetime.timedelta( + days=PnD, + seconds=seconds, + microseconds=microseconds, + minutes=TnM, + hours=TnH, + weeks=PnW, + ) + + @classmethod + def build_interval(cls, start=None, end=None, duration=None): + start, end, duration = cls.range_check_interval(start, end, duration) + + if start is not None and end is not None: + # / + startobject = cls._build_object(start) + endobject = cls._build_object(end) + + return (startobject, endobject) + + durationobject = cls._build_object(duration) + + # Determine if datetime promotion is required + datetimerequired = ( + duration.TnH is not None + or duration.TnM is not None + or duration.TnS is not None + or durationobject.seconds != 0 + or durationobject.microseconds != 0 + ) + + if end is not None: + # / + endobject = cls._build_object(end) + + # Range check + if type(end) is DateTuple and datetimerequired is True: + # is a date, and requires datetime resolution + return ( + endobject, + cls.build_datetime(end, TupleBuilder.build_time()) - durationobject, + ) + + return (endobject, endobject - durationobject) + + # / + startobject = cls._build_object(start) + + # Range check + if type(start) is DateTuple and datetimerequired is True: + # is a date, and requires datetime resolution + return ( + startobject, + cls.build_datetime(start, TupleBuilder.build_time()) + durationobject, + ) + + return (startobject, startobject + durationobject) + + @classmethod + def build_repeating_interval(cls, R=None, Rnn=None, interval=None): + startobject = None + endobject = None + + R, Rnn, interval = cls.range_check_repeating_interval(R, Rnn, interval) + + if interval.start is not None: + startobject = cls._build_object(interval.start) + + if interval.end is not None: + endobject = cls._build_object(interval.end) + + if interval.duration is not None: + durationobject = cls._build_object(interval.duration) + else: + durationobject = endobject - startobject + + if R is True: + if startobject is not None: + return cls._date_generator_unbounded(startobject, durationobject) + + return cls._date_generator_unbounded(endobject, -durationobject) + + iterations = int(Rnn) + + if startobject is not None: + return cls._date_generator(startobject, durationobject, iterations) + + return cls._date_generator(endobject, -durationobject, iterations) + + @classmethod + def build_timezone(cls, negative=None, Z=None, hh=None, mm=None, name=""): + negative, Z, hh, mm, name = cls.range_check_timezone(negative, Z, hh, mm, name) + + if Z is True: + # Z -> UTC + return UTCOffset(name="UTC", minutes=0) + + tzhour = int(hh) + + if mm is not None: + tzminute = int(mm) + else: + tzminute = 0 + + if negative is True: + return UTCOffset(name=name, minutes=-(tzhour * 60 + tzminute)) + + return UTCOffset(name=name, minutes=tzhour * 60 + tzminute) + + @classmethod + def range_check_duration( + cls, + PnY=None, + PnM=None, + PnW=None, + PnD=None, + TnH=None, + TnM=None, + TnS=None, + rangedict=None, + ): + years = 0 + months = 0 + days = 0 + weeks = 0 + hours = 0 + minutes = 0 + seconds = 0 + microseconds = 0 + + PnY, PnM, PnW, PnD, TnH, TnM, TnS = BaseTimeBuilder.range_check_duration( + PnY, PnM, PnW, PnD, TnH, TnM, TnS, rangedict=cls.DURATION_RANGE_DICT + ) + + if PnY is not None: + if type(PnY) is FractionalComponent: + years = PnY.principal + microseconds = PnY.microsecondremainder + else: + years = PnY + + if years * DAYS_PER_YEAR > TIMEDELTA_MAX_DAYS: + raise YearOutOfBoundsError("Duration exceeds maximum timedelta size.") + + if PnM is not None: + if type(PnM) is FractionalComponent: + months = PnM.principal + microseconds = PnM.microsecondremainder + else: + months = PnM + + if months * DAYS_PER_MONTH > TIMEDELTA_MAX_DAYS: + raise MonthOutOfBoundsError("Duration exceeds maximum timedelta size.") + + if PnW is not None: + if type(PnW) is FractionalComponent: + weeks = PnW.principal + microseconds = PnW.microsecondremainder + else: + weeks = PnW + + if weeks * DAYS_PER_WEEK > TIMEDELTA_MAX_DAYS: + raise WeekOutOfBoundsError("Duration exceeds maximum timedelta size.") + + if PnD is not None: + if type(PnD) is FractionalComponent: + days = PnD.principal + microseconds = PnD.microsecondremainder + else: + days = PnD + + if days > TIMEDELTA_MAX_DAYS: + raise DayOutOfBoundsError("Duration exceeds maximum timedelta size.") + + if TnH is not None: + if type(TnH) is FractionalComponent: + hours = TnH.principal + microseconds = TnH.microsecondremainder + else: + hours = TnH + + if hours // HOURS_PER_DAY > TIMEDELTA_MAX_DAYS: + raise HoursOutOfBoundsError("Duration exceeds maximum timedelta size.") + + if TnM is not None: + if type(TnM) is FractionalComponent: + minutes = TnM.principal + microseconds = TnM.microsecondremainder + else: + minutes = TnM + + if minutes // MINUTES_PER_DAY > TIMEDELTA_MAX_DAYS: + raise MinutesOutOfBoundsError( + "Duration exceeds maximum timedelta size." + ) + + if TnS is not None: + if type(TnS) is FractionalComponent: + seconds = TnS.principal + microseconds = TnS.microsecondremainder + else: + seconds = TnS + + if seconds // SECONDS_PER_DAY > TIMEDELTA_MAX_DAYS: + raise SecondsOutOfBoundsError( + "Duration exceeds maximum timedelta size." + ) + + ( + years, + months, + weeks, + days, + hours, + minutes, + seconds, + microseconds, + ) = PythonTimeBuilder._distribute_microseconds( + microseconds, + (years, months, weeks, days, hours, minutes, seconds), + ( + MICROSECONDS_PER_YEAR, + MICROSECONDS_PER_MONTH, + MICROSECONDS_PER_WEEK, + MICROSECONDS_PER_DAY, + MICROSECONDS_PER_HOUR, + MICROSECONDS_PER_MINUTE, + MICROSECONDS_PER_SECOND, + ), + ) + + # Note that weeks can be handled without conversion to days + totaldays = years * DAYS_PER_YEAR + months * DAYS_PER_MONTH + days + + # Check against timedelta limits + if ( + totaldays + + weeks * DAYS_PER_WEEK + + hours // HOURS_PER_DAY + + minutes // MINUTES_PER_DAY + + seconds // SECONDS_PER_DAY + > TIMEDELTA_MAX_DAYS + ): + raise DayOutOfBoundsError("Duration exceeds maximum timedelta size.") + + return ( + None, + None, + weeks, + totaldays, + hours, + minutes, + FractionalComponent(seconds, microseconds), + ) + + @classmethod + def range_check_interval(cls, start=None, end=None, duration=None): + # Handles concise format, range checks any potential durations + if start is not None and end is not None: + # / + # Handle concise format + if cls._is_interval_end_concise(end) is True: + end = cls._combine_concise_interval_tuples(start, end) + + return (start, end, duration) + + durationobject = cls._build_object(duration) + + if end is not None: + # / + endobject = cls._build_object(end) + + # Range check + if type(end) is DateTuple: + enddatetime = cls.build_datetime(end, TupleBuilder.build_time()) + + if enddatetime - datetime.datetime.min < durationobject: + raise YearOutOfBoundsError("Interval end less than minimium date.") + else: + mindatetime = datetime.datetime.min + + if end.time.tz is not None: + mindatetime = mindatetime.replace(tzinfo=endobject.tzinfo) + + if endobject - mindatetime < durationobject: + raise YearOutOfBoundsError("Interval end less than minimium date.") + else: + # / + startobject = cls._build_object(start) + + # Range check + if type(start) is DateTuple: + startdatetime = cls.build_datetime(start, TupleBuilder.build_time()) + + if datetime.datetime.max - startdatetime < durationobject: + raise YearOutOfBoundsError( + "Interval end greater than maximum date." + ) + else: + maxdatetime = datetime.datetime.max + + if start.time.tz is not None: + maxdatetime = maxdatetime.replace(tzinfo=startobject.tzinfo) + + if maxdatetime - startobject < durationobject: + raise YearOutOfBoundsError( + "Interval end greater than maximum date." + ) + + return (start, end, duration) + + @staticmethod + def _build_week_date(isoyear, isoweek, isoday=None): + if isoday is None: + return PythonTimeBuilder._iso_year_start(isoyear) + datetime.timedelta( + weeks=isoweek - 1 + ) + + return PythonTimeBuilder._iso_year_start(isoyear) + datetime.timedelta( + weeks=isoweek - 1, days=isoday - 1 + ) + + @staticmethod + def _build_ordinal_date(isoyear, isoday): + # Day of year to a date + # https://stackoverflow.com/questions/2427555/python-question-year-and-day-of-year-to-date + builtdate = datetime.date(isoyear, 1, 1) + datetime.timedelta(days=isoday - 1) + + return builtdate + + @staticmethod + def _iso_year_start(isoyear): + # Given an ISO year, returns the equivalent of the start of the year + # on the Gregorian calendar (which is used by Python) + # Stolen from: + # http://stackoverflow.com/questions/304256/whats-the-best-way-to-find-the-inverse-of-datetime-isocalendar + + # Determine the location of the 4th of January, the first week of + # the ISO year is the week containing the 4th of January + # http://en.wikipedia.org/wiki/ISO_week_date + fourth_jan = datetime.date(isoyear, 1, 4) + + # Note the conversion from ISO day (1 - 7) and Python day (0 - 6) + delta = datetime.timedelta(days=fourth_jan.isoweekday() - 1) + + # Return the start of the year + return fourth_jan - delta + + @staticmethod + def _date_generator(startdate, timedelta, iterations): + currentdate = startdate + currentiteration = 0 + + while currentiteration < iterations: + yield currentdate + + # Update the values + currentdate += timedelta + currentiteration += 1 + + @staticmethod + def _date_generator_unbounded(startdate, timedelta): + currentdate = startdate + + while True: + yield currentdate + + # Update the value + currentdate += timedelta + + @staticmethod + def _distribute_microseconds(todistribute, recipients, reductions): + # Given a number of microseconds as int, a tuple of ints length n + # to distribute to, and a tuple of ints length n to divide todistribute + # by (from largest to smallest), returns a tuple of length n + 1, with + # todistribute divided across recipients using the reductions, with + # the final remainder returned as the final tuple member + results = [] + + remainder = todistribute + + for index, reduction in enumerate(reductions): + additional, remainder = divmod(remainder, reduction) + + results.append(recipients[index] + additional) + + # Always return the remaining microseconds + results.append(remainder) + + return tuple(results) diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__init__.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__init__.py new file mode 100644 index 000000000..1a94e017a --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/__init__.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 000000000..51acd12e5 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/__init__.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/test_init.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/test_init.cpython-38.pyc new file mode 100644 index 000000000..2e45683f0 Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/test_init.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/test_python.cpython-38.pyc b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/test_python.cpython-38.pyc new file mode 100644 index 000000000..ab3b7159c Binary files /dev/null and b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/__pycache__/test_python.cpython-38.pyc differ diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/test_init.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/test_init.py new file mode 100644 index 000000000..7c9f092c7 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/test_init.py @@ -0,0 +1,838 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +import unittest + +import aniso8601 +from aniso8601.builders import ( + BaseTimeBuilder, + DatetimeTuple, + DateTuple, + DurationTuple, + IntervalTuple, + RepeatingIntervalTuple, + TimeTuple, + TimezoneTuple, + TupleBuilder, + cast, +) +from aniso8601.exceptions import ( + DayOutOfBoundsError, + HoursOutOfBoundsError, + ISOFormatError, + LeapSecondError, + MidnightBoundsError, + MinutesOutOfBoundsError, + MonthOutOfBoundsError, + SecondsOutOfBoundsError, + WeekOutOfBoundsError, +) +from aniso8601.tests.compat import mock + + +class LeapSecondSupportingTestBuilder(BaseTimeBuilder): + LEAP_SECONDS_SUPPORTED = True + + +class TestBuilderFunctions(unittest.TestCase): + def test_cast(self): + self.assertEqual(cast("1", int), 1) + self.assertEqual(cast("-2", int), -2) + self.assertEqual(cast("3", float), float(3)) + self.assertEqual(cast("-4", float), float(-4)) + self.assertEqual(cast("5.6", float), 5.6) + self.assertEqual(cast("-7.8", float), -7.8) + + def test_cast_exception(self): + with self.assertRaises(ISOFormatError): + cast("asdf", int) + + with self.assertRaises(ISOFormatError): + cast("asdf", float) + + def test_cast_caughtexception(self): + def tester(value): + raise RuntimeError + + with self.assertRaises(ISOFormatError): + cast("asdf", tester, caughtexceptions=(RuntimeError,)) + + def test_cast_thrownexception(self): + with self.assertRaises(RuntimeError): + cast("asdf", int, thrownexception=RuntimeError) + + +class TestBaseTimeBuilder(unittest.TestCase): + def test_build_date(self): + with self.assertRaises(NotImplementedError): + BaseTimeBuilder.build_date() + + def test_build_time(self): + with self.assertRaises(NotImplementedError): + BaseTimeBuilder.build_time() + + def test_build_datetime(self): + with self.assertRaises(NotImplementedError): + BaseTimeBuilder.build_datetime(None, None) + + def test_build_duration(self): + with self.assertRaises(NotImplementedError): + BaseTimeBuilder.build_duration() + + def test_build_interval(self): + with self.assertRaises(NotImplementedError): + BaseTimeBuilder.build_interval() + + def test_build_repeating_interval(self): + with self.assertRaises(NotImplementedError): + BaseTimeBuilder.build_repeating_interval() + + def test_build_timezone(self): + with self.assertRaises(NotImplementedError): + BaseTimeBuilder.build_timezone() + + def test_range_check_date(self): + # Check the calendar for day ranges + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="0007", MM="02", DD="30") + + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="0007", DDD="366") + + with self.assertRaises(MonthOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="4333", MM="30", DD="30") + + # 0 isn't a valid week number + with self.assertRaises(WeekOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="2003", Www="00") + + # Week must not be larger than 53 + with self.assertRaises(WeekOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="2004", Www="54") + + # 0 isn't a valid day number + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="2001", Www="02", D="0") + + # Day must not be larger than 7 + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="2001", Www="02", D="8") + + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="1981", DDD="000") + + # Day must be 365, or 366, not larger + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="1234", DDD="000") + + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="1234", DDD="367") + + # https://bitbucket.org/nielsenb/aniso8601/issues/14/parsing-ordinal-dates-should-only-allow + with self.assertRaises(DayOutOfBoundsError): + BaseTimeBuilder.range_check_date(YYYY="1981", DDD="366") + + # Make sure Nones pass through unmodified + self.assertEqual( + BaseTimeBuilder.range_check_date(rangedict={}), + (None, None, None, None, None, None), + ) + + def test_range_check_time(self): + # Leap seconds not supported + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + # https://bitbucket.org/nielsenb/aniso8601/issues/13/parsing-of-leap-second-gives-wildly + with self.assertRaises(LeapSecondError): + BaseTimeBuilder.range_check_time(hh="23", mm="59", ss="60") + + with self.assertRaises(SecondsOutOfBoundsError): + BaseTimeBuilder.range_check_time(hh="00", mm="00", ss="60") + + with self.assertRaises(SecondsOutOfBoundsError): + BaseTimeBuilder.range_check_time(hh="00", mm="00", ss="61") + + with self.assertRaises(MinutesOutOfBoundsError): + BaseTimeBuilder.range_check_time(hh="00", mm="61") + + with self.assertRaises(MinutesOutOfBoundsError): + BaseTimeBuilder.range_check_time(hh="00", mm="60") + + with self.assertRaises(MinutesOutOfBoundsError): + BaseTimeBuilder.range_check_time(hh="00", mm="60.1") + + with self.assertRaises(HoursOutOfBoundsError): + BaseTimeBuilder.range_check_time(hh="25") + + # Hour 24 can only represent midnight + with self.assertRaises(MidnightBoundsError): + BaseTimeBuilder.range_check_time(hh="24", mm="00", ss="01") + + with self.assertRaises(MidnightBoundsError): + BaseTimeBuilder.range_check_time(hh="24", mm="00.1") + + with self.assertRaises(MidnightBoundsError): + BaseTimeBuilder.range_check_time(hh="24", mm="01") + + with self.assertRaises(MidnightBoundsError): + BaseTimeBuilder.range_check_time(hh="24.1") + + # Leap seconds not supported + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + # https://bitbucket.org/nielsenb/aniso8601/issues/13/parsing-of-leap-second-gives-wildly + with self.assertRaises(LeapSecondError): + BaseTimeBuilder.range_check_time(hh="23", mm="59", ss="60") + + # Make sure Nones pass through unmodified + self.assertEqual( + BaseTimeBuilder.range_check_time(rangedict={}), (None, None, None, None) + ) + + def test_range_check_time_leap_seconds_supported(self): + self.assertEqual( + LeapSecondSupportingTestBuilder.range_check_time(hh="23", mm="59", ss="60"), + (23, 59, 60, None), + ) + + with self.assertRaises(SecondsOutOfBoundsError): + LeapSecondSupportingTestBuilder.range_check_time(hh="01", mm="02", ss="60") + + def test_range_check_duration(self): + self.assertEqual( + BaseTimeBuilder.range_check_duration(), + (None, None, None, None, None, None, None), + ) + + self.assertEqual( + BaseTimeBuilder.range_check_duration(rangedict={}), + (None, None, None, None, None, None, None), + ) + + def test_range_check_repeating_interval(self): + self.assertEqual( + BaseTimeBuilder.range_check_repeating_interval(), (None, None, None) + ) + + self.assertEqual( + BaseTimeBuilder.range_check_repeating_interval(rangedict={}), + (None, None, None), + ) + + def test_range_check_timezone(self): + self.assertEqual( + BaseTimeBuilder.range_check_timezone(), (None, None, None, None, "") + ) + + self.assertEqual( + BaseTimeBuilder.range_check_timezone(rangedict={}), + (None, None, None, None, ""), + ) + + def test_build_object(self): + datetest = ( + DateTuple("1", "2", "3", "4", "5", "6"), + {"YYYY": "1", "MM": "2", "DD": "3", "Www": "4", "D": "5", "DDD": "6"}, + ) + + timetest = ( + TimeTuple("1", "2", "3", TimezoneTuple(False, False, "4", "5", "tz name")), + { + "hh": "1", + "mm": "2", + "ss": "3", + "tz": TimezoneTuple(False, False, "4", "5", "tz name"), + }, + ) + + datetimetest = ( + DatetimeTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + TimeTuple( + "7", "8", "9", TimezoneTuple(True, False, "10", "11", "tz name") + ), + ), + ( + DateTuple("1", "2", "3", "4", "5", "6"), + TimeTuple( + "7", "8", "9", TimezoneTuple(True, False, "10", "11", "tz name") + ), + ), + ) + + durationtest = ( + DurationTuple("1", "2", "3", "4", "5", "6", "7"), + { + "PnY": "1", + "PnM": "2", + "PnW": "3", + "PnD": "4", + "TnH": "5", + "TnM": "6", + "TnS": "7", + }, + ) + + intervaltests = ( + ( + IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + DateTuple("7", "8", "9", "10", "11", "12"), + None, + ), + { + "start": DateTuple("1", "2", "3", "4", "5", "6"), + "end": DateTuple("7", "8", "9", "10", "11", "12"), + "duration": None, + }, + ), + ( + IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + None, + DurationTuple("7", "8", "9", "10", "11", "12", "13"), + ), + { + "start": DateTuple("1", "2", "3", "4", "5", "6"), + "end": None, + "duration": DurationTuple("7", "8", "9", "10", "11", "12", "13"), + }, + ), + ( + IntervalTuple( + None, + TimeTuple( + "1", "2", "3", TimezoneTuple(True, False, "4", "5", "tz name") + ), + DurationTuple("6", "7", "8", "9", "10", "11", "12"), + ), + { + "start": None, + "end": TimeTuple( + "1", "2", "3", TimezoneTuple(True, False, "4", "5", "tz name") + ), + "duration": DurationTuple("6", "7", "8", "9", "10", "11", "12"), + }, + ), + ) + + repeatingintervaltests = ( + ( + RepeatingIntervalTuple( + True, + None, + IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + DateTuple("7", "8", "9", "10", "11", "12"), + None, + ), + ), + { + "R": True, + "Rnn": None, + "interval": IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + DateTuple("7", "8", "9", "10", "11", "12"), + None, + ), + }, + ), + ( + RepeatingIntervalTuple( + False, + "1", + IntervalTuple( + DatetimeTuple( + DateTuple("2", "3", "4", "5", "6", "7"), + TimeTuple("8", "9", "10", None), + ), + DatetimeTuple( + DateTuple("11", "12", "13", "14", "15", "16"), + TimeTuple("17", "18", "19", None), + ), + None, + ), + ), + { + "R": False, + "Rnn": "1", + "interval": IntervalTuple( + DatetimeTuple( + DateTuple("2", "3", "4", "5", "6", "7"), + TimeTuple("8", "9", "10", None), + ), + DatetimeTuple( + DateTuple("11", "12", "13", "14", "15", "16"), + TimeTuple("17", "18", "19", None), + ), + None, + ), + }, + ), + ) + + timezonetest = ( + TimezoneTuple(False, False, "1", "2", "+01:02"), + {"negative": False, "Z": False, "hh": "1", "mm": "2", "name": "+01:02"}, + ) + + with mock.patch.object( + aniso8601.builders.BaseTimeBuilder, "build_date" + ) as mock_build: + mock_build.return_value = datetest[0] + + result = BaseTimeBuilder._build_object(datetest[0]) + + self.assertEqual(result, datetest[0]) + mock_build.assert_called_once_with(**datetest[1]) + + with mock.patch.object( + aniso8601.builders.BaseTimeBuilder, "build_time" + ) as mock_build: + mock_build.return_value = timetest[0] + + result = BaseTimeBuilder._build_object(timetest[0]) + + self.assertEqual(result, timetest[0]) + mock_build.assert_called_once_with(**timetest[1]) + + with mock.patch.object( + aniso8601.builders.BaseTimeBuilder, "build_datetime" + ) as mock_build: + mock_build.return_value = datetimetest[0] + + result = BaseTimeBuilder._build_object(datetimetest[0]) + + self.assertEqual(result, datetimetest[0]) + mock_build.assert_called_once_with(*datetimetest[1]) + + with mock.patch.object( + aniso8601.builders.BaseTimeBuilder, "build_duration" + ) as mock_build: + mock_build.return_value = durationtest[0] + + result = BaseTimeBuilder._build_object(durationtest[0]) + + self.assertEqual(result, durationtest[0]) + mock_build.assert_called_once_with(**durationtest[1]) + + for intervaltest in intervaltests: + with mock.patch.object( + aniso8601.builders.BaseTimeBuilder, "build_interval" + ) as mock_build: + mock_build.return_value = intervaltest[0] + + result = BaseTimeBuilder._build_object(intervaltest[0]) + + self.assertEqual(result, intervaltest[0]) + mock_build.assert_called_once_with(**intervaltest[1]) + + for repeatingintervaltest in repeatingintervaltests: + with mock.patch.object( + aniso8601.builders.BaseTimeBuilder, "build_repeating_interval" + ) as mock_build: + mock_build.return_value = repeatingintervaltest[0] + + result = BaseTimeBuilder._build_object(repeatingintervaltest[0]) + + self.assertEqual(result, repeatingintervaltest[0]) + mock_build.assert_called_once_with(**repeatingintervaltest[1]) + + with mock.patch.object( + aniso8601.builders.BaseTimeBuilder, "build_timezone" + ) as mock_build: + mock_build.return_value = timezonetest[0] + + result = BaseTimeBuilder._build_object(timezonetest[0]) + + self.assertEqual(result, timezonetest[0]) + mock_build.assert_called_once_with(**timezonetest[1]) + + def test_is_interval_end_concise(self): + self.assertTrue( + BaseTimeBuilder._is_interval_end_concise(TimeTuple("1", "2", "3", None)) + ) + self.assertTrue( + BaseTimeBuilder._is_interval_end_concise( + DateTuple(None, "2", "3", "4", "5", "6") + ) + ) + self.assertTrue( + BaseTimeBuilder._is_interval_end_concise( + DatetimeTuple( + DateTuple(None, "2", "3", "4", "5", "6"), + TimeTuple("7", "8", "9", None), + ) + ) + ) + + self.assertFalse( + BaseTimeBuilder._is_interval_end_concise( + DateTuple("1", "2", "3", "4", "5", "6") + ) + ) + self.assertFalse( + BaseTimeBuilder._is_interval_end_concise( + DatetimeTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + TimeTuple("7", "8", "9", None), + ) + ) + ) + + def test_combine_concise_interval_tuples(self): + testtuples = ( + ( + DateTuple("2020", "01", "01", None, None, None), + DateTuple(None, None, "02", None, None, None), + DateTuple("2020", "01", "02", None, None, None), + ), + ( + DateTuple("2008", "02", "15", None, None, None), + DateTuple(None, "03", "14", None, None, None), + DateTuple("2008", "03", "14", None, None, None), + ), + ( + DatetimeTuple( + DateTuple("2007", "12", "14", None, None, None), + TimeTuple("13", "30", None, None), + ), + TimeTuple("15", "30", None, None), + DatetimeTuple( + DateTuple("2007", "12", "14", None, None, None), + TimeTuple("15", "30", None, None), + ), + ), + ( + DatetimeTuple( + DateTuple("2007", "11", "13", None, None, None), + TimeTuple("09", "00", None, None), + ), + DatetimeTuple( + DateTuple(None, None, "15", None, None, None), + TimeTuple("17", "00", None, None), + ), + DatetimeTuple( + DateTuple("2007", "11", "15", None, None, None), + TimeTuple("17", "00", None, None), + ), + ), + ( + DatetimeTuple( + DateTuple("2007", "11", "13", None, None, None), + TimeTuple("00", "00", None, None), + ), + DatetimeTuple( + DateTuple(None, None, "16", None, None, None), + TimeTuple("00", "00", None, None), + ), + DatetimeTuple( + DateTuple("2007", "11", "16", None, None, None), + TimeTuple("00", "00", None, None), + ), + ), + ( + DatetimeTuple( + DateTuple("2007", "11", "13", None, None, None), + TimeTuple( + "09", "00", None, TimezoneTuple(False, True, None, None, "Z") + ), + ), + DatetimeTuple( + DateTuple(None, None, "15", None, None, None), + TimeTuple("17", "00", None, None), + ), + DatetimeTuple( + DateTuple("2007", "11", "15", None, None, None), + TimeTuple( + "17", "00", None, TimezoneTuple(False, True, None, None, "Z") + ), + ), + ), + ) + + for testtuple in testtuples: + result = BaseTimeBuilder._combine_concise_interval_tuples( + testtuple[0], testtuple[1] + ) + self.assertEqual(result, testtuple[2]) + + +class TestTupleBuilder(unittest.TestCase): + def test_build_date(self): + datetuple = TupleBuilder.build_date() + + self.assertEqual(datetuple, DateTuple(None, None, None, None, None, None)) + + datetuple = TupleBuilder.build_date( + YYYY="1", MM="2", DD="3", Www="4", D="5", DDD="6" + ) + + self.assertEqual(datetuple, DateTuple("1", "2", "3", "4", "5", "6")) + + def test_build_time(self): + testtuples = ( + ({}, TimeTuple(None, None, None, None)), + ( + {"hh": "1", "mm": "2", "ss": "3", "tz": None}, + TimeTuple("1", "2", "3", None), + ), + ( + { + "hh": "1", + "mm": "2", + "ss": "3", + "tz": TimezoneTuple(False, False, "4", "5", "tz name"), + }, + TimeTuple( + "1", "2", "3", TimezoneTuple(False, False, "4", "5", "tz name") + ), + ), + ) + + for testtuple in testtuples: + self.assertEqual(TupleBuilder.build_time(**testtuple[0]), testtuple[1]) + + def test_build_datetime(self): + testtuples = ( + ( + { + "date": DateTuple("1", "2", "3", "4", "5", "6"), + "time": TimeTuple("7", "8", "9", None), + }, + DatetimeTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + TimeTuple("7", "8", "9", None), + ), + ), + ( + { + "date": DateTuple("1", "2", "3", "4", "5", "6"), + "time": TimeTuple( + "7", "8", "9", TimezoneTuple(True, False, "10", "11", "tz name") + ), + }, + DatetimeTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + TimeTuple( + "7", "8", "9", TimezoneTuple(True, False, "10", "11", "tz name") + ), + ), + ), + ) + + for testtuple in testtuples: + self.assertEqual(TupleBuilder.build_datetime(**testtuple[0]), testtuple[1]) + + def test_build_duration(self): + testtuples = ( + ({}, DurationTuple(None, None, None, None, None, None, None)), + ( + { + "PnY": "1", + "PnM": "2", + "PnW": "3", + "PnD": "4", + "TnH": "5", + "TnM": "6", + "TnS": "7", + }, + DurationTuple("1", "2", "3", "4", "5", "6", "7"), + ), + ) + + for testtuple in testtuples: + self.assertEqual(TupleBuilder.build_duration(**testtuple[0]), testtuple[1]) + + def test_build_interval(self): + testtuples = ( + ({}, IntervalTuple(None, None, None)), + ( + { + "start": DateTuple("1", "2", "3", "4", "5", "6"), + "end": DateTuple("7", "8", "9", "10", "11", "12"), + }, + IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + DateTuple("7", "8", "9", "10", "11", "12"), + None, + ), + ), + ( + { + "start": TimeTuple( + "1", "2", "3", TimezoneTuple(True, False, "7", "8", "tz name") + ), + "end": TimeTuple( + "4", "5", "6", TimezoneTuple(False, False, "9", "10", "tz name") + ), + }, + IntervalTuple( + TimeTuple( + "1", "2", "3", TimezoneTuple(True, False, "7", "8", "tz name") + ), + TimeTuple( + "4", "5", "6", TimezoneTuple(False, False, "9", "10", "tz name") + ), + None, + ), + ), + ( + { + "start": DatetimeTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + TimeTuple( + "7", + "8", + "9", + TimezoneTuple(True, False, "10", "11", "tz name"), + ), + ), + "end": DatetimeTuple( + DateTuple("12", "13", "14", "15", "16", "17"), + TimeTuple( + "18", + "19", + "20", + TimezoneTuple(False, False, "21", "22", "tz name"), + ), + ), + }, + IntervalTuple( + DatetimeTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + TimeTuple( + "7", + "8", + "9", + TimezoneTuple(True, False, "10", "11", "tz name"), + ), + ), + DatetimeTuple( + DateTuple("12", "13", "14", "15", "16", "17"), + TimeTuple( + "18", + "19", + "20", + TimezoneTuple(False, False, "21", "22", "tz name"), + ), + ), + None, + ), + ), + ( + { + "start": DateTuple("1", "2", "3", "4", "5", "6"), + "end": None, + "duration": DurationTuple("7", "8", "9", "10", "11", "12", "13"), + }, + IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + None, + DurationTuple("7", "8", "9", "10", "11", "12", "13"), + ), + ), + ( + { + "start": None, + "end": TimeTuple( + "1", "2", "3", TimezoneTuple(True, False, "4", "5", "tz name") + ), + "duration": DurationTuple("6", "7", "8", "9", "10", "11", "12"), + }, + IntervalTuple( + None, + TimeTuple( + "1", "2", "3", TimezoneTuple(True, False, "4", "5", "tz name") + ), + DurationTuple("6", "7", "8", "9", "10", "11", "12"), + ), + ), + ) + + for testtuple in testtuples: + self.assertEqual(TupleBuilder.build_interval(**testtuple[0]), testtuple[1]) + + def test_build_repeating_interval(self): + testtuples = ( + ({}, RepeatingIntervalTuple(None, None, None)), + ( + { + "R": True, + "interval": IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + DateTuple("7", "8", "9", "10", "11", "12"), + None, + ), + }, + RepeatingIntervalTuple( + True, + None, + IntervalTuple( + DateTuple("1", "2", "3", "4", "5", "6"), + DateTuple("7", "8", "9", "10", "11", "12"), + None, + ), + ), + ), + ( + { + "R": False, + "Rnn": "1", + "interval": IntervalTuple( + DatetimeTuple( + DateTuple("2", "3", "4", "5", "6", "7"), + TimeTuple("8", "9", "10", None), + ), + DatetimeTuple( + DateTuple("11", "12", "13", "14", "15", "16"), + TimeTuple("17", "18", "19", None), + ), + None, + ), + }, + RepeatingIntervalTuple( + False, + "1", + IntervalTuple( + DatetimeTuple( + DateTuple("2", "3", "4", "5", "6", "7"), + TimeTuple("8", "9", "10", None), + ), + DatetimeTuple( + DateTuple("11", "12", "13", "14", "15", "16"), + TimeTuple("17", "18", "19", None), + ), + None, + ), + ), + ), + ) + + for testtuple in testtuples: + result = TupleBuilder.build_repeating_interval(**testtuple[0]) + self.assertEqual(result, testtuple[1]) + + def test_build_timezone(self): + testtuples = ( + ({}, TimezoneTuple(None, None, None, None, "")), + ( + {"negative": False, "Z": True, "name": "UTC"}, + TimezoneTuple(False, True, None, None, "UTC"), + ), + ( + {"negative": False, "Z": False, "hh": "1", "mm": "2", "name": "+01:02"}, + TimezoneTuple(False, False, "1", "2", "+01:02"), + ), + ( + {"negative": True, "Z": False, "hh": "1", "mm": "2", "name": "-01:02"}, + TimezoneTuple(True, False, "1", "2", "-01:02"), + ), + ) + + for testtuple in testtuples: + result = TupleBuilder.build_timezone(**testtuple[0]) + self.assertEqual(result, testtuple[1]) diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/test_python.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/test_python.py new file mode 100644 index 000000000..11111a163 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/builders/tests/test_python.py @@ -0,0 +1,1710 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +import datetime +import unittest + +from aniso8601 import compat +from aniso8601.builders import ( + DatetimeTuple, + DateTuple, + DurationTuple, + IntervalTuple, + Limit, + TimeTuple, + TimezoneTuple, +) +from aniso8601.builders.python import ( + FractionalComponent, + PythonTimeBuilder, + _cast_to_fractional_component, + fractional_range_check, + year_range_check, +) +from aniso8601.exceptions import ( + DayOutOfBoundsError, + HoursOutOfBoundsError, + ISOFormatError, + LeapSecondError, + MidnightBoundsError, + MinutesOutOfBoundsError, + MonthOutOfBoundsError, + SecondsOutOfBoundsError, + WeekOutOfBoundsError, + YearOutOfBoundsError, +) +from aniso8601.utcoffset import UTCOffset + + +class TestPythonTimeBuilder_UtiltyFunctions(unittest.TestCase): + def test_year_range_check(self): + yearlimit = Limit( + "Invalid year string.", + 0000, + 9999, + YearOutOfBoundsError, + "Year must be between 1..9999.", + None, + ) + + self.assertEqual(year_range_check("1", yearlimit), 1000) + + def test_fractional_range_check(self): + limit = Limit( + "Invalid string.", -1, 1, ValueError, "Value must be between -1..1.", None + ) + + self.assertEqual(fractional_range_check(10, "1", limit), 1) + self.assertEqual(fractional_range_check(10, "-1", limit), -1) + self.assertEqual( + fractional_range_check(10, "0.1", limit), FractionalComponent(0, 1) + ) + self.assertEqual( + fractional_range_check(10, "-0.1", limit), FractionalComponent(-0, 1) + ) + + with self.assertRaises(ValueError): + fractional_range_check(10, "1.1", limit) + + with self.assertRaises(ValueError): + fractional_range_check(10, "-1.1", limit) + + def test_cast_to_fractional_component(self): + self.assertEqual( + _cast_to_fractional_component(10, "1.1"), FractionalComponent(1, 1) + ) + self.assertEqual( + _cast_to_fractional_component(10, "-1.1"), FractionalComponent(-1, 1) + ) + + self.assertEqual( + _cast_to_fractional_component(100, "1.1"), FractionalComponent(1, 10) + ) + self.assertEqual( + _cast_to_fractional_component(100, "-1.1"), FractionalComponent(-1, 10) + ) + + +class TestPythonTimeBuilder(unittest.TestCase): + def test_build_date(self): + testtuples = ( + ( + { + "YYYY": "2013", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(2013, 1, 1), + ), + ( + { + "YYYY": "0001", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(1, 1, 1), + ), + ( + { + "YYYY": "1900", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(1900, 1, 1), + ), + ( + { + "YYYY": "1981", + "MM": "04", + "DD": "05", + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(1981, 4, 5), + ), + ( + { + "YYYY": "1981", + "MM": "04", + "DD": None, + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(1981, 4, 1), + ), + ( + { + "YYYY": "1981", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": "095", + }, + datetime.date(1981, 4, 5), + ), + ( + { + "YYYY": "1981", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": "365", + }, + datetime.date(1981, 12, 31), + ), + ( + { + "YYYY": "1980", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": "366", + }, + datetime.date(1980, 12, 31), + ), + # Make sure we shift in zeros + ( + { + "YYYY": "1", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(1000, 1, 1), + ), + ( + { + "YYYY": "12", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(1200, 1, 1), + ), + ( + { + "YYYY": "123", + "MM": None, + "DD": None, + "Www": None, + "D": None, + "DDD": None, + }, + datetime.date(1230, 1, 1), + ), + ) + + for testtuple in testtuples: + result = PythonTimeBuilder.build_date(**testtuple[0]) + self.assertEqual(result, testtuple[1]) + + # Test weekday + testtuples = ( + ( + { + "YYYY": "2004", + "MM": None, + "DD": None, + "Www": "53", + "D": None, + "DDD": None, + }, + datetime.date(2004, 12, 27), + 0, + ), + ( + { + "YYYY": "2009", + "MM": None, + "DD": None, + "Www": "01", + "D": None, + "DDD": None, + }, + datetime.date(2008, 12, 29), + 0, + ), + ( + { + "YYYY": "2010", + "MM": None, + "DD": None, + "Www": "01", + "D": None, + "DDD": None, + }, + datetime.date(2010, 1, 4), + 0, + ), + ( + { + "YYYY": "2009", + "MM": None, + "DD": None, + "Www": "53", + "D": None, + "DDD": None, + }, + datetime.date(2009, 12, 28), + 0, + ), + ( + { + "YYYY": "2009", + "MM": None, + "DD": None, + "Www": "01", + "D": "1", + "DDD": None, + }, + datetime.date(2008, 12, 29), + 0, + ), + ( + { + "YYYY": "2009", + "MM": None, + "DD": None, + "Www": "53", + "D": "7", + "DDD": None, + }, + datetime.date(2010, 1, 3), + 6, + ), + ( + { + "YYYY": "2010", + "MM": None, + "DD": None, + "Www": "01", + "D": "1", + "DDD": None, + }, + datetime.date(2010, 1, 4), + 0, + ), + ( + { + "YYYY": "2004", + "MM": None, + "DD": None, + "Www": "53", + "D": "6", + "DDD": None, + }, + datetime.date(2005, 1, 1), + 5, + ), + ) + + for testtuple in testtuples: + result = PythonTimeBuilder.build_date(**testtuple[0]) + self.assertEqual(result, testtuple[1]) + self.assertEqual(result.weekday(), testtuple[2]) + + def test_build_time(self): + testtuples = ( + ({}, datetime.time()), + ({"hh": "12.5"}, datetime.time(hour=12, minute=30)), + ( + {"hh": "23.99999999997"}, + datetime.time(hour=23, minute=59, second=59, microsecond=999999), + ), + ({"hh": "1", "mm": "23"}, datetime.time(hour=1, minute=23)), + ( + {"hh": "1", "mm": "23.4567"}, + datetime.time(hour=1, minute=23, second=27, microsecond=402000), + ), + ( + {"hh": "14", "mm": "43.999999997"}, + datetime.time(hour=14, minute=43, second=59, microsecond=999999), + ), + ( + {"hh": "1", "mm": "23", "ss": "45"}, + datetime.time(hour=1, minute=23, second=45), + ), + ( + {"hh": "23", "mm": "21", "ss": "28.512400"}, + datetime.time(hour=23, minute=21, second=28, microsecond=512400), + ), + ( + {"hh": "01", "mm": "03", "ss": "11.858714"}, + datetime.time(hour=1, minute=3, second=11, microsecond=858714), + ), + ( + {"hh": "14", "mm": "43", "ss": "59.9999997"}, + datetime.time(hour=14, minute=43, second=59, microsecond=999999), + ), + ({"hh": "24"}, datetime.time(hour=0)), + ({"hh": "24", "mm": "00"}, datetime.time(hour=0)), + ({"hh": "24", "mm": "00", "ss": "00"}, datetime.time(hour=0)), + ( + {"tz": TimezoneTuple(False, None, "00", "00", "UTC")}, + datetime.time(tzinfo=UTCOffset(name="UTC", minutes=0)), + ), + ( + { + "hh": "23", + "mm": "21", + "ss": "28.512400", + "tz": TimezoneTuple(False, None, "00", "00", "+00:00"), + }, + datetime.time( + hour=23, + minute=21, + second=28, + microsecond=512400, + tzinfo=UTCOffset(name="+00:00", minutes=0), + ), + ), + ( + { + "hh": "1", + "mm": "23", + "tz": TimezoneTuple(False, None, "01", "00", "+1"), + }, + datetime.time( + hour=1, minute=23, tzinfo=UTCOffset(name="+1", minutes=60) + ), + ), + ( + { + "hh": "1", + "mm": "23.4567", + "tz": TimezoneTuple(True, None, "01", "00", "-1"), + }, + datetime.time( + hour=1, + minute=23, + second=27, + microsecond=402000, + tzinfo=UTCOffset(name="-1", minutes=-60), + ), + ), + ( + { + "hh": "23", + "mm": "21", + "ss": "28.512400", + "tz": TimezoneTuple(False, None, "01", "30", "+1:30"), + }, + datetime.time( + hour=23, + minute=21, + second=28, + microsecond=512400, + tzinfo=UTCOffset(name="+1:30", minutes=90), + ), + ), + ( + { + "hh": "23", + "mm": "21", + "ss": "28.512400", + "tz": TimezoneTuple(False, None, "11", "15", "+11:15"), + }, + datetime.time( + hour=23, + minute=21, + second=28, + microsecond=512400, + tzinfo=UTCOffset(name="+11:15", minutes=675), + ), + ), + ( + { + "hh": "23", + "mm": "21", + "ss": "28.512400", + "tz": TimezoneTuple(False, None, "12", "34", "+12:34"), + }, + datetime.time( + hour=23, + minute=21, + second=28, + microsecond=512400, + tzinfo=UTCOffset(name="+12:34", minutes=754), + ), + ), + ( + { + "hh": "23", + "mm": "21", + "ss": "28.512400", + "tz": TimezoneTuple(False, None, "00", "00", "UTC"), + }, + datetime.time( + hour=23, + minute=21, + second=28, + microsecond=512400, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + ), + # Make sure we truncate, not round + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + # https://bitbucket.org/nielsenb/aniso8601/issues/21/sub-microsecond-precision-is-lost-when + ( + {"hh": "14.9999999999999999"}, + datetime.time(hour=14, minute=59, second=59, microsecond=999999), + ), + ({"mm": "0.00000000999"}, datetime.time()), + ({"mm": "0.0000000999"}, datetime.time(microsecond=5)), + ({"ss": "0.0000001"}, datetime.time()), + ({"ss": "2.0000048"}, datetime.time(second=2, microsecond=4)), + ) + + for testtuple in testtuples: + result = PythonTimeBuilder.build_time(**testtuple[0]) + self.assertEqual(result, testtuple[1]) + + def test_build_datetime(self): + testtuples = ( + ( + ( + DateTuple("2019", "06", "05", None, None, None), + TimeTuple("01", "03", "11.858714", None), + ), + datetime.datetime( + 2019, 6, 5, hour=1, minute=3, second=11, microsecond=858714 + ), + ), + ( + ( + DateTuple("1234", "02", "03", None, None, None), + TimeTuple("23", "21", "28.512400", None), + ), + datetime.datetime( + 1234, 2, 3, hour=23, minute=21, second=28, microsecond=512400 + ), + ), + ( + ( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple( + "23", + "21", + "28.512400", + TimezoneTuple(False, None, "11", "15", "+11:15"), + ), + ), + datetime.datetime( + 1981, + 4, + 5, + hour=23, + minute=21, + second=28, + microsecond=512400, + tzinfo=UTCOffset(name="+11:15", minutes=675), + ), + ), + ) + + for testtuple in testtuples: + result = PythonTimeBuilder.build_datetime(*testtuple[0]) + self.assertEqual(result, testtuple[1]) + + def test_build_duration(self): + testtuples = ( + ( + { + "PnY": "1", + "PnM": "2", + "PnD": "3", + "TnH": "4", + "TnM": "54", + "TnS": "6", + }, + datetime.timedelta(days=428, hours=4, minutes=54, seconds=6), + ), + ( + { + "PnY": "1", + "PnM": "2", + "PnD": "3", + "TnH": "4", + "TnM": "54", + "TnS": "6.5", + }, + datetime.timedelta(days=428, hours=4, minutes=54, seconds=6.5), + ), + ({"PnY": "1", "PnM": "2", "PnD": "3"}, datetime.timedelta(days=428)), + ({"PnY": "1", "PnM": "2", "PnD": "3.5"}, datetime.timedelta(days=428.5)), + ( + {"TnH": "4", "TnM": "54", "TnS": "6.5"}, + datetime.timedelta(hours=4, minutes=54, seconds=6.5), + ), + ( + {"TnH": "1", "TnM": "3", "TnS": "11.858714"}, + datetime.timedelta(hours=1, minutes=3, seconds=11, microseconds=858714), + ), + ( + {"TnH": "4", "TnM": "54", "TnS": "28.512400"}, + datetime.timedelta( + hours=4, minutes=54, seconds=28, microseconds=512400 + ), + ), + # Make sure we truncate, not round + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + # https://bitbucket.org/nielsenb/aniso8601/issues/21/sub-microsecond-precision-is-lost-when + ( + {"PnY": "1999.9999999999999999"}, + datetime.timedelta(days=729999, seconds=86399, microseconds=999999), + ), + ( + {"PnM": "1.9999999999999999"}, + datetime.timedelta( + days=59, hours=23, minutes=59, seconds=59, microseconds=999999 + ), + ), + ( + {"PnW": "1.9999999999999999"}, + datetime.timedelta( + days=13, hours=23, minutes=59, seconds=59, microseconds=999999 + ), + ), + ( + {"PnD": "1.9999999999999999"}, + datetime.timedelta( + days=1, hours=23, minutes=59, seconds=59, microseconds=999999 + ), + ), + ( + {"TnH": "14.9999999999999999"}, + datetime.timedelta( + hours=14, minutes=59, seconds=59, microseconds=999999 + ), + ), + ({"TnM": "0.00000000999"}, datetime.timedelta(0)), + ({"TnM": "0.0000000999"}, datetime.timedelta(microseconds=5)), + ({"TnS": "0.0000001"}, datetime.timedelta(0)), + ({"TnS": "2.0000048"}, datetime.timedelta(seconds=2, microseconds=4)), + ({"PnY": "1"}, datetime.timedelta(days=365)), + ({"PnY": "1.5"}, datetime.timedelta(days=547.5)), + ({"PnM": "1"}, datetime.timedelta(days=30)), + ({"PnM": "1.5"}, datetime.timedelta(days=45)), + ({"PnW": "1"}, datetime.timedelta(days=7)), + ({"PnW": "1.5"}, datetime.timedelta(days=10.5)), + ({"PnD": "1"}, datetime.timedelta(days=1)), + ({"PnD": "1.5"}, datetime.timedelta(days=1.5)), + ( + { + "PnY": "0003", + "PnM": "06", + "PnD": "04", + "TnH": "12", + "TnM": "30", + "TnS": "05", + }, + datetime.timedelta(days=1279, hours=12, minutes=30, seconds=5), + ), + ( + { + "PnY": "0003", + "PnM": "06", + "PnD": "04", + "TnH": "12", + "TnM": "30", + "TnS": "05.5", + }, + datetime.timedelta(days=1279, hours=12, minutes=30, seconds=5.5), + ), + # Test timedelta limit + ( + {"PnD": "999999999", "TnH": "23", "TnM": "59", "TnS": "59.999999"}, + datetime.timedelta.max, + ), + # Make sure we truncate, not round + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + ( + { + "PnY": "0001", + "PnM": "02", + "PnD": "03", + "TnH": "14", + "TnM": "43", + "TnS": "59.9999997", + }, + datetime.timedelta( + days=428, hours=14, minutes=43, seconds=59, microseconds=999999 + ), + ), + # Verify overflows + ({"TnH": "36"}, datetime.timedelta(days=1, hours=12)), + ) + + for testtuple in testtuples: + result = PythonTimeBuilder.build_duration(**testtuple[0]) + self.assertEqual(result, testtuple[1]) + + def test_build_interval(self): + testtuples = ( + ( + { + "end": DatetimeTuple( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + "duration": DurationTuple(None, "1", None, None, None, None, None), + }, + datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1), + datetime.datetime(year=1981, month=3, day=6, hour=1, minute=1), + ), + ( + { + "end": DateTuple("1981", "04", "05", None, None, None), + "duration": DurationTuple(None, "1", None, None, None, None, None), + }, + datetime.date(year=1981, month=4, day=5), + datetime.date(year=1981, month=3, day=6), + ), + ( + { + "end": DateTuple("2018", "03", "06", None, None, None), + "duration": DurationTuple( + "1.5", None, None, None, None, None, None + ), + }, + datetime.date(year=2018, month=3, day=6), + datetime.datetime(year=2016, month=9, day=4, hour=12), + ), + ( + { + "end": DateTuple("2014", "11", "12", None, None, None), + "duration": DurationTuple(None, None, None, None, "1", None, None), + }, + datetime.date(year=2014, month=11, day=12), + datetime.datetime(year=2014, month=11, day=11, hour=23), + ), + ( + { + "end": DateTuple("2014", "11", "12", None, None, None), + "duration": DurationTuple(None, None, None, None, "4", "54", "6.5"), + }, + datetime.date(year=2014, month=11, day=12), + datetime.datetime( + year=2014, + month=11, + day=11, + hour=19, + minute=5, + second=53, + microsecond=500000, + ), + ), + ( + { + "end": DatetimeTuple( + DateTuple("2050", "03", "01", None, None, None), + TimeTuple( + "13", + "00", + "00", + TimezoneTuple(False, True, None, None, "Z"), + ), + ), + "duration": DurationTuple(None, None, None, None, "10", None, None), + }, + datetime.datetime( + year=2050, + month=3, + day=1, + hour=13, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + datetime.datetime( + year=2050, + month=3, + day=1, + hour=3, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + ), + # Make sure we truncate, not round + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + # https://bitbucket.org/nielsenb/aniso8601/issues/21/sub-microsecond-precision-is-lost-when + ( + { + "end": DateTuple("2000", "01", "01", None, None, None), + "duration": DurationTuple( + "1999.9999999999999999", None, None, None, None, None, None + ), + }, + datetime.date(year=2000, month=1, day=1), + datetime.datetime( + year=1, month=4, day=30, hour=0, minute=0, second=0, microsecond=1 + ), + ), + ( + { + "end": DateTuple("1989", "03", "01", None, None, None), + "duration": DurationTuple( + None, "1.9999999999999999", None, None, None, None, None + ), + }, + datetime.date(year=1989, month=3, day=1), + datetime.datetime( + year=1988, + month=12, + day=31, + hour=0, + minute=0, + second=0, + microsecond=1, + ), + ), + ( + { + "end": DateTuple("1989", "03", "01", None, None, None), + "duration": DurationTuple( + None, None, "1.9999999999999999", None, None, None, None + ), + }, + datetime.date(year=1989, month=3, day=1), + datetime.datetime( + year=1989, + month=2, + day=15, + hour=0, + minute=0, + second=0, + microsecond=1, + ), + ), + ( + { + "end": DateTuple("1989", "03", "01", None, None, None), + "duration": DurationTuple( + None, None, None, "1.9999999999999999", None, None, None + ), + }, + datetime.date(year=1989, month=3, day=1), + datetime.datetime( + year=1989, + month=2, + day=27, + hour=0, + minute=0, + second=0, + microsecond=1, + ), + ), + ( + { + "end": DateTuple("2001", "01", "01", None, None, None), + "duration": DurationTuple( + None, None, None, None, "14.9999999999999999", None, None + ), + }, + datetime.date(year=2001, month=1, day=1), + datetime.datetime( + year=2000, + month=12, + day=31, + hour=9, + minute=0, + second=0, + microsecond=1, + ), + ), + ( + { + "end": DateTuple("2001", "01", "01", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, "0.00000000999", None + ), + }, + datetime.date(year=2001, month=1, day=1), + datetime.datetime(year=2001, month=1, day=1), + ), + ( + { + "end": DateTuple("2001", "01", "01", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, "0.0000000999", None + ), + }, + datetime.date(year=2001, month=1, day=1), + datetime.datetime( + year=2000, + month=12, + day=31, + hour=23, + minute=59, + second=59, + microsecond=999995, + ), + ), + ( + { + "end": DateTuple("2018", "03", "06", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, None, "0.0000001" + ), + }, + datetime.date(year=2018, month=3, day=6), + datetime.datetime(year=2018, month=3, day=6), + ), + ( + { + "end": DateTuple("2018", "03", "06", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, None, "2.0000048" + ), + }, + datetime.date(year=2018, month=3, day=6), + datetime.datetime( + year=2018, + month=3, + day=5, + hour=23, + minute=59, + second=57, + microsecond=999996, + ), + ), + ( + { + "start": DatetimeTuple( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + "duration": DurationTuple(None, "1", None, "1", None, "1", None), + }, + datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1), + datetime.datetime(year=1981, month=5, day=6, hour=1, minute=2), + ), + ( + { + "start": DateTuple("1981", "04", "05", None, None, None), + "duration": DurationTuple(None, "1", None, "1", None, None, None), + }, + datetime.date(year=1981, month=4, day=5), + datetime.date(year=1981, month=5, day=6), + ), + ( + { + "start": DateTuple("2018", "03", "06", None, None, None), + "duration": DurationTuple( + None, "2.5", None, None, None, None, None + ), + }, + datetime.date(year=2018, month=3, day=6), + datetime.date(year=2018, month=5, day=20), + ), + ( + { + "start": DateTuple("2014", "11", "12", None, None, None), + "duration": DurationTuple(None, None, None, None, "1", None, None), + }, + datetime.date(year=2014, month=11, day=12), + datetime.datetime(year=2014, month=11, day=12, hour=1, minute=0), + ), + ( + { + "start": DateTuple("2014", "11", "12", None, None, None), + "duration": DurationTuple(None, None, None, None, "4", "54", "6.5"), + }, + datetime.date(year=2014, month=11, day=12), + datetime.datetime( + year=2014, + month=11, + day=12, + hour=4, + minute=54, + second=6, + microsecond=500000, + ), + ), + ( + { + "start": DatetimeTuple( + DateTuple("2050", "03", "01", None, None, None), + TimeTuple( + "13", + "00", + "00", + TimezoneTuple(False, True, None, None, "Z"), + ), + ), + "duration": DurationTuple(None, None, None, None, "10", None, None), + }, + datetime.datetime( + year=2050, + month=3, + day=1, + hour=13, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + datetime.datetime( + year=2050, + month=3, + day=1, + hour=23, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + ), + # Make sure we truncate, not round + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + ( + { + "start": DateTuple("0001", "01", "01", None, None, None), + "duration": DurationTuple( + "1999.9999999999999999", None, None, None, None, None, None + ), + }, + datetime.date(year=1, month=1, day=1), + datetime.datetime( + year=1999, + month=9, + day=3, + hour=23, + minute=59, + second=59, + microsecond=999999, + ), + ), + ( + { + "start": DateTuple("1989", "03", "01", None, None, None), + "duration": DurationTuple( + None, "1.9999999999999999", None, None, None, None, None + ), + }, + datetime.date(year=1989, month=3, day=1), + datetime.datetime( + year=1989, + month=4, + day=29, + hour=23, + minute=59, + second=59, + microsecond=999999, + ), + ), + ( + { + "start": DateTuple("1989", "03", "01", None, None, None), + "duration": DurationTuple( + None, None, "1.9999999999999999", None, None, None, None + ), + }, + datetime.date(year=1989, month=3, day=1), + datetime.datetime( + year=1989, + month=3, + day=14, + hour=23, + minute=59, + second=59, + microsecond=999999, + ), + ), + ( + { + "start": DateTuple("1989", "03", "01", None, None, None), + "duration": DurationTuple( + None, None, None, "1.9999999999999999", None, None, None + ), + }, + datetime.date(year=1989, month=3, day=1), + datetime.datetime( + year=1989, + month=3, + day=2, + hour=23, + minute=59, + second=59, + microsecond=999999, + ), + ), + ( + { + "start": DateTuple("2001", "01", "01", None, None, None), + "duration": DurationTuple( + None, None, None, None, "14.9999999999999999", None, None + ), + }, + datetime.date(year=2001, month=1, day=1), + datetime.datetime( + year=2001, + month=1, + day=1, + hour=14, + minute=59, + second=59, + microsecond=999999, + ), + ), + ( + { + "start": DateTuple("2001", "01", "01", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, "0.00000000999", None + ), + }, + datetime.date(year=2001, month=1, day=1), + datetime.datetime(year=2001, month=1, day=1), + ), + ( + { + "start": DateTuple("2001", "01", "01", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, "0.0000000999", None + ), + }, + datetime.date(year=2001, month=1, day=1), + datetime.datetime( + year=2001, month=1, day=1, hour=0, minute=0, second=0, microsecond=5 + ), + ), + ( + { + "start": DateTuple("2018", "03", "06", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, None, "0.0000001" + ), + }, + datetime.date(year=2018, month=3, day=6), + datetime.datetime(year=2018, month=3, day=6), + ), + ( + { + "start": DateTuple("2018", "03", "06", None, None, None), + "duration": DurationTuple( + None, None, None, None, None, None, "2.0000048" + ), + }, + datetime.date(year=2018, month=3, day=6), + datetime.datetime( + year=2018, month=3, day=6, hour=0, minute=0, second=2, microsecond=4 + ), + ), + ( + { + "start": DatetimeTuple( + DateTuple("1980", "03", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + "end": DatetimeTuple( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + }, + datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1), + datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1), + ), + ( + { + "start": DatetimeTuple( + DateTuple("1980", "03", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + "end": DateTuple("1981", "04", "05", None, None, None), + }, + datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1), + datetime.date(year=1981, month=4, day=5), + ), + ( + { + "start": DateTuple("1980", "03", "05", None, None, None), + "end": DatetimeTuple( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + }, + datetime.date(year=1980, month=3, day=5), + datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1), + ), + ( + { + "start": DateTuple("1980", "03", "05", None, None, None), + "end": DateTuple("1981", "04", "05", None, None, None), + }, + datetime.date(year=1980, month=3, day=5), + datetime.date(year=1981, month=4, day=5), + ), + ( + { + "start": DateTuple("1981", "04", "05", None, None, None), + "end": DateTuple("1980", "03", "05", None, None, None), + }, + datetime.date(year=1981, month=4, day=5), + datetime.date(year=1980, month=3, day=5), + ), + ( + { + "start": DatetimeTuple( + DateTuple("2050", "03", "01", None, None, None), + TimeTuple( + "13", + "00", + "00", + TimezoneTuple(False, True, None, None, "Z"), + ), + ), + "end": DatetimeTuple( + DateTuple("2050", "05", "11", None, None, None), + TimeTuple( + "15", + "30", + "00", + TimezoneTuple(False, True, None, None, "Z"), + ), + ), + }, + datetime.datetime( + year=2050, + month=3, + day=1, + hour=13, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + datetime.datetime( + year=2050, + month=5, + day=11, + hour=15, + minute=30, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + ), + # Test concise representation + ( + { + "start": DateTuple("2020", "01", "01", None, None, None), + "end": DateTuple(None, None, "02", None, None, None), + }, + datetime.date(year=2020, month=1, day=1), + datetime.date(year=2020, month=1, day=2), + ), + ( + { + "start": DateTuple("2008", "02", "15", None, None, None), + "end": DateTuple(None, "03", "14", None, None, None), + }, + datetime.date(year=2008, month=2, day=15), + datetime.date(year=2008, month=3, day=14), + ), + ( + { + "start": DatetimeTuple( + DateTuple("2007", "12", "14", None, None, None), + TimeTuple("13", "30", None, None), + ), + "end": TimeTuple("15", "30", None, None), + }, + datetime.datetime(year=2007, month=12, day=14, hour=13, minute=30), + datetime.datetime(year=2007, month=12, day=14, hour=15, minute=30), + ), + ( + { + "start": DatetimeTuple( + DateTuple("2007", "11", "13", None, None, None), + TimeTuple("09", "00", None, None), + ), + "end": DatetimeTuple( + DateTuple(None, None, "15", None, None, None), + TimeTuple("17", "00", None, None), + ), + }, + datetime.datetime(year=2007, month=11, day=13, hour=9), + datetime.datetime(year=2007, month=11, day=15, hour=17), + ), + ( + { + "start": DatetimeTuple( + DateTuple("2007", "11", "13", None, None, None), + TimeTuple("00", "00", None, None), + ), + "end": DatetimeTuple( + DateTuple(None, None, "16", None, None, None), + TimeTuple("00", "00", None, None), + ), + }, + datetime.datetime(year=2007, month=11, day=13), + datetime.datetime(year=2007, month=11, day=16), + ), + ( + { + "start": DatetimeTuple( + DateTuple("2007", "11", "13", None, None, None), + TimeTuple( + "09", + "00", + None, + TimezoneTuple(False, True, None, None, "Z"), + ), + ), + "end": DatetimeTuple( + DateTuple(None, None, "15", None, None, None), + TimeTuple("17", "00", None, None), + ), + }, + datetime.datetime( + year=2007, + month=11, + day=13, + hour=9, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + datetime.datetime( + year=2007, + month=11, + day=15, + hour=17, + tzinfo=UTCOffset(name="UTC", minutes=0), + ), + ), + ( + { + "start": DatetimeTuple( + DateTuple("2007", "11", "13", None, None, None), + TimeTuple("09", "00", None, None), + ), + "end": TimeTuple("12", "34.567", None, None), + }, + datetime.datetime(year=2007, month=11, day=13, hour=9), + datetime.datetime( + year=2007, + month=11, + day=13, + hour=12, + minute=34, + second=34, + microsecond=20000, + ), + ), + ( + { + "start": DateTuple("2007", "11", "13", None, None, None), + "end": TimeTuple("12", "34", None, None), + }, + datetime.date(year=2007, month=11, day=13), + datetime.datetime(year=2007, month=11, day=13, hour=12, minute=34), + ), + # Make sure we truncate, not round + # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is + ( + { + "start": DatetimeTuple( + DateTuple("1980", "03", "05", None, None, None), + TimeTuple("01", "01", "00.0000001", None), + ), + "end": DatetimeTuple( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple("14", "43", "59.9999997", None), + ), + }, + datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1), + datetime.datetime( + year=1981, + month=4, + day=5, + hour=14, + minute=43, + second=59, + microsecond=999999, + ), + ), + ) + + for testtuple in testtuples: + result = PythonTimeBuilder.build_interval(**testtuple[0]) + self.assertEqual(result[0], testtuple[1]) + self.assertEqual(result[1], testtuple[2]) + + def test_build_repeating_interval(self): + args = { + "Rnn": "3", + "interval": IntervalTuple( + DateTuple("1981", "04", "05", None, None, None), + None, + DurationTuple(None, None, None, "1", None, None, None), + ), + } + results = list(PythonTimeBuilder.build_repeating_interval(**args)) + + self.assertEqual(results[0], datetime.date(year=1981, month=4, day=5)) + self.assertEqual(results[1], datetime.date(year=1981, month=4, day=6)) + self.assertEqual(results[2], datetime.date(year=1981, month=4, day=7)) + + args = { + "Rnn": "11", + "interval": IntervalTuple( + None, + DatetimeTuple( + DateTuple("1980", "03", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + DurationTuple(None, None, None, None, "1", "2", None), + ), + } + results = list(PythonTimeBuilder.build_repeating_interval(**args)) + + for dateindex in compat.range(0, 11): + self.assertEqual( + results[dateindex], + datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1) + - dateindex * datetime.timedelta(hours=1, minutes=2), + ) + + args = { + "Rnn": "2", + "interval": IntervalTuple( + DatetimeTuple( + DateTuple("1980", "03", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + DatetimeTuple( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + None, + ), + } + results = list(PythonTimeBuilder.build_repeating_interval(**args)) + + self.assertEqual( + results[0], datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1) + ) + self.assertEqual( + results[1], datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1) + ) + + args = { + "Rnn": "2", + "interval": IntervalTuple( + DatetimeTuple( + DateTuple("1980", "03", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + DatetimeTuple( + DateTuple("1981", "04", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + None, + ), + } + results = list(PythonTimeBuilder.build_repeating_interval(**args)) + + self.assertEqual( + results[0], datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1) + ) + self.assertEqual( + results[1], datetime.datetime(year=1981, month=4, day=5, hour=1, minute=1) + ) + + args = { + "R": True, + "interval": IntervalTuple( + None, + DatetimeTuple( + DateTuple("1980", "03", "05", None, None, None), + TimeTuple("01", "01", "00", None), + ), + DurationTuple(None, None, None, None, "1", "2", None), + ), + } + resultgenerator = PythonTimeBuilder.build_repeating_interval(**args) + + # Test the first 11 generated + for dateindex in compat.range(0, 11): + self.assertEqual( + next(resultgenerator), + datetime.datetime(year=1980, month=3, day=5, hour=1, minute=1) + - dateindex * datetime.timedelta(hours=1, minutes=2), + ) + + args = { + "R": True, + "interval": IntervalTuple( + DateTuple("1981", "04", "05", None, None, None), + None, + DurationTuple(None, None, None, "1", None, None, None), + ), + } + resultgenerator = PythonTimeBuilder.build_repeating_interval(**args) + + # Test the first 11 generated + for dateindex in compat.range(0, 11): + self.assertEqual( + next(resultgenerator), + ( + datetime.datetime(year=1981, month=4, day=5, hour=0, minute=0) + + dateindex * datetime.timedelta(days=1) + ).date(), + ) + + def test_build_timezone(self): + testtuples = ( + ({"Z": True, "name": "Z"}, datetime.timedelta(hours=0), "UTC"), + ( + {"negative": False, "hh": "00", "mm": "00", "name": "+00:00"}, + datetime.timedelta(hours=0), + "+00:00", + ), + ( + {"negative": False, "hh": "01", "mm": "00", "name": "+01:00"}, + datetime.timedelta(hours=1), + "+01:00", + ), + ( + {"negative": True, "hh": "01", "mm": "00", "name": "-01:00"}, + -datetime.timedelta(hours=1), + "-01:00", + ), + ( + {"negative": False, "hh": "00", "mm": "12", "name": "+00:12"}, + datetime.timedelta(minutes=12), + "+00:12", + ), + ( + {"negative": False, "hh": "01", "mm": "23", "name": "+01:23"}, + datetime.timedelta(hours=1, minutes=23), + "+01:23", + ), + ( + {"negative": True, "hh": "01", "mm": "23", "name": "-01:23"}, + -datetime.timedelta(hours=1, minutes=23), + "-01:23", + ), + ( + {"negative": False, "hh": "00", "name": "+00"}, + datetime.timedelta(hours=0), + "+00", + ), + ( + {"negative": False, "hh": "01", "name": "+01"}, + datetime.timedelta(hours=1), + "+01", + ), + ( + {"negative": True, "hh": "01", "name": "-01"}, + -datetime.timedelta(hours=1), + "-01", + ), + ( + {"negative": False, "hh": "12", "name": "+12"}, + datetime.timedelta(hours=12), + "+12", + ), + ( + {"negative": True, "hh": "12", "name": "-12"}, + -datetime.timedelta(hours=12), + "-12", + ), + ) + + for testtuple in testtuples: + result = PythonTimeBuilder.build_timezone(**testtuple[0]) + self.assertEqual(result.utcoffset(None), testtuple[1]) + self.assertEqual(result.tzname(None), testtuple[2]) + + def test_range_check_date(self): + # 0 isn't a valid year for a Python builder + with self.assertRaises(YearOutOfBoundsError): + PythonTimeBuilder.build_date(YYYY="0000") + + # Leap year + # https://bitbucket.org/nielsenb/aniso8601/issues/14/parsing-ordinal-dates-should-only-allow + with self.assertRaises(DayOutOfBoundsError): + PythonTimeBuilder.build_date(YYYY="1981", DDD="366") + + def test_range_check_time(self): + # Hour 24 can only represent midnight + with self.assertRaises(MidnightBoundsError): + PythonTimeBuilder.build_time(hh="24", mm="00", ss="01") + + with self.assertRaises(MidnightBoundsError): + PythonTimeBuilder.build_time(hh="24", mm="00.1") + + with self.assertRaises(MidnightBoundsError): + PythonTimeBuilder.build_time(hh="24", mm="01") + + with self.assertRaises(MidnightBoundsError): + PythonTimeBuilder.build_time(hh="24.1") + + def test_range_check_duration(self): + with self.assertRaises(YearOutOfBoundsError): + PythonTimeBuilder.build_duration( + PnY=str((datetime.timedelta.max.days // 365) + 1) + ) + + with self.assertRaises(MonthOutOfBoundsError): + PythonTimeBuilder.build_duration( + PnM=str((datetime.timedelta.max.days // 30) + 1) + ) + + with self.assertRaises(DayOutOfBoundsError): + PythonTimeBuilder.build_duration(PnD=str(datetime.timedelta.max.days + 1)) + + with self.assertRaises(WeekOutOfBoundsError): + PythonTimeBuilder.build_duration( + PnW=str((datetime.timedelta.max.days // 7) + 1) + ) + + with self.assertRaises(HoursOutOfBoundsError): + PythonTimeBuilder.build_duration( + TnH=str((datetime.timedelta.max.days * 24) + 24) + ) + + with self.assertRaises(MinutesOutOfBoundsError): + PythonTimeBuilder.build_duration( + TnM=str((datetime.timedelta.max.days * 24 * 60) + 24 * 60) + ) + + with self.assertRaises(SecondsOutOfBoundsError): + PythonTimeBuilder.build_duration( + TnS=str((datetime.timedelta.max.days * 24 * 60 * 60) + 24 * 60 * 60) + ) + + # Split max range across all parts + maxpart = datetime.timedelta.max.days // 7 + + with self.assertRaises(DayOutOfBoundsError): + PythonTimeBuilder.build_duration( + PnY=str((maxpart // 365) + 1), + PnM=str((maxpart // 30) + 1), + PnD=str((maxpart + 1)), + PnW=str((maxpart // 7) + 1), + TnH=str((maxpart * 24) + 1), + TnM=str((maxpart * 24 * 60) + 1), + TnS=str((maxpart * 24 * 60 * 60) + 1), + ) + + def test_range_check_interval(self): + with self.assertRaises(YearOutOfBoundsError): + PythonTimeBuilder.build_interval( + start=DateTuple("0007", None, None, None, None, None), + duration=DurationTuple( + None, None, None, str(datetime.timedelta.max.days), None, None, None + ), + ) + + with self.assertRaises(YearOutOfBoundsError): + PythonTimeBuilder.build_interval( + start=DatetimeTuple( + DateTuple("0007", None, None, None, None, None), + TimeTuple("1", None, None, None), + ), + duration=DurationTuple( + str(datetime.timedelta.max.days // 365), + None, + None, + None, + None, + None, + None, + ), + ) + + with self.assertRaises(YearOutOfBoundsError): + PythonTimeBuilder.build_interval( + end=DateTuple("0001", None, None, None, None, None), + duration=DurationTuple("3", None, None, None, None, None, None), + ) + + with self.assertRaises(YearOutOfBoundsError): + PythonTimeBuilder.build_interval( + end=DatetimeTuple( + DateTuple("0001", None, None, None, None, None), + TimeTuple("1", None, None, None), + ), + duration=DurationTuple("2", None, None, None, None, None, None), + ) + + def test_build_week_date(self): + weekdate = PythonTimeBuilder._build_week_date(2009, 1) + self.assertEqual(weekdate, datetime.date(year=2008, month=12, day=29)) + + weekdate = PythonTimeBuilder._build_week_date(2009, 53, isoday=7) + self.assertEqual(weekdate, datetime.date(year=2010, month=1, day=3)) + + def test_build_ordinal_date(self): + ordinaldate = PythonTimeBuilder._build_ordinal_date(1981, 95) + self.assertEqual(ordinaldate, datetime.date(year=1981, month=4, day=5)) + + def test_iso_year_start(self): + yearstart = PythonTimeBuilder._iso_year_start(2004) + self.assertEqual(yearstart, datetime.date(year=2003, month=12, day=29)) + + yearstart = PythonTimeBuilder._iso_year_start(2010) + self.assertEqual(yearstart, datetime.date(year=2010, month=1, day=4)) + + yearstart = PythonTimeBuilder._iso_year_start(2009) + self.assertEqual(yearstart, datetime.date(year=2008, month=12, day=29)) + + def test_date_generator(self): + startdate = datetime.date(year=2018, month=8, day=29) + timedelta = datetime.timedelta(days=1) + iterations = 10 + + generator = PythonTimeBuilder._date_generator(startdate, timedelta, iterations) + + results = list(generator) + + for dateindex in compat.range(0, 10): + self.assertEqual( + results[dateindex], + datetime.date(year=2018, month=8, day=29) + + dateindex * datetime.timedelta(days=1), + ) + + def test_date_generator_unbounded(self): + startdate = datetime.date(year=2018, month=8, day=29) + timedelta = datetime.timedelta(days=5) + + generator = PythonTimeBuilder._date_generator_unbounded(startdate, timedelta) + + # Check the first 10 results + for dateindex in compat.range(0, 10): + self.assertEqual( + next(generator), + datetime.date(year=2018, month=8, day=29) + + dateindex * datetime.timedelta(days=5), + ) + + def test_distribute_microseconds(self): + self.assertEqual(PythonTimeBuilder._distribute_microseconds(1, (), ()), (1,)) + self.assertEqual( + PythonTimeBuilder._distribute_microseconds(11, (0,), (10,)), (1, 1) + ) + self.assertEqual( + PythonTimeBuilder._distribute_microseconds(211, (0, 0), (100, 10)), + (2, 1, 1), + ) + + self.assertEqual(PythonTimeBuilder._distribute_microseconds(1, (), ()), (1,)) + self.assertEqual( + PythonTimeBuilder._distribute_microseconds(11, (5,), (10,)), (6, 1) + ) + self.assertEqual( + PythonTimeBuilder._distribute_microseconds(211, (10, 5), (100, 10)), + (12, 6, 1), + ) diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/compat.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/compat.py new file mode 100644 index 000000000..25af5794a --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/compat.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +import sys + +PY2 = sys.version_info[0] == 2 + +if PY2: # pragma: no cover + range = xrange # pylint: disable=undefined-variable +else: + range = range + + +def is_string(tocheck): + # pylint: disable=undefined-variable + if PY2: # pragma: no cover + return isinstance(tocheck, str) or isinstance(tocheck, unicode) + + return isinstance(tocheck, str) diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/date.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/date.py new file mode 100644 index 000000000..ea0cf9c59 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/date.py @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +from aniso8601.builders import TupleBuilder +from aniso8601.builders.python import PythonTimeBuilder +from aniso8601.compat import is_string +from aniso8601.exceptions import ISOFormatError +from aniso8601.resolution import DateResolution + + +def get_date_resolution(isodatestr): + # Valid string formats are: + # + # Y[YYY] + # YYYY-MM-DD + # YYYYMMDD + # YYYY-MM + # YYYY-Www + # YYYYWww + # YYYY-Www-D + # YYYYWwwD + # YYYY-DDD + # YYYYDDD + isodatetuple = parse_date(isodatestr, builder=TupleBuilder) + + if isodatetuple.DDD is not None: + # YYYY-DDD + # YYYYDDD + return DateResolution.Ordinal + + if isodatetuple.D is not None: + # YYYY-Www-D + # YYYYWwwD + return DateResolution.Weekday + + if isodatetuple.Www is not None: + # YYYY-Www + # YYYYWww + return DateResolution.Week + + if isodatetuple.DD is not None: + # YYYY-MM-DD + # YYYYMMDD + return DateResolution.Day + + if isodatetuple.MM is not None: + # YYYY-MM + return DateResolution.Month + + # Y[YYY] + return DateResolution.Year + + +def parse_date(isodatestr, builder=PythonTimeBuilder): + # Given a string in any ISO 8601 date format, return a datetime.date + # object that corresponds to the given date. Valid string formats are: + # + # Y[YYY] + # YYYY-MM-DD + # YYYYMMDD + # YYYY-MM + # YYYY-Www + # YYYYWww + # YYYY-Www-D + # YYYYWwwD + # YYYY-DDD + # YYYYDDD + if is_string(isodatestr) is False: + raise ValueError("Date must be string.") + + if isodatestr.startswith("+") or isodatestr.startswith("-"): + raise NotImplementedError( + "ISO 8601 extended year representation " "not supported." + ) + + if len(isodatestr) == 0 or isodatestr.count("-") > 2: + raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr)) + yearstr = None + monthstr = None + daystr = None + weekstr = None + weekdaystr = None + ordinaldaystr = None + + if len(isodatestr) <= 4: + # Y[YYY] + yearstr = isodatestr + elif "W" in isodatestr: + if len(isodatestr) == 10: + # YYYY-Www-D + yearstr = isodatestr[0:4] + weekstr = isodatestr[6:8] + weekdaystr = isodatestr[9] + elif len(isodatestr) == 8: + if "-" in isodatestr: + # YYYY-Www + yearstr = isodatestr[0:4] + weekstr = isodatestr[6:] + else: + # YYYYWwwD + yearstr = isodatestr[0:4] + weekstr = isodatestr[5:7] + weekdaystr = isodatestr[7] + elif len(isodatestr) == 7: + # YYYYWww + yearstr = isodatestr[0:4] + weekstr = isodatestr[5:] + elif len(isodatestr) == 7: + if "-" in isodatestr: + # YYYY-MM + yearstr = isodatestr[0:4] + monthstr = isodatestr[5:] + else: + # YYYYDDD + yearstr = isodatestr[0:4] + ordinaldaystr = isodatestr[4:] + elif len(isodatestr) == 8: + if "-" in isodatestr: + # YYYY-DDD + yearstr = isodatestr[0:4] + ordinaldaystr = isodatestr[5:] + else: + # YYYYMMDD + yearstr = isodatestr[0:4] + monthstr = isodatestr[4:6] + daystr = isodatestr[6:] + elif len(isodatestr) == 10: + # YYYY-MM-DD + yearstr = isodatestr[0:4] + monthstr = isodatestr[5:7] + daystr = isodatestr[8:] + else: + raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr)) + + hascomponent = False + + for componentstr in [yearstr, monthstr, daystr, weekstr, weekdaystr, ordinaldaystr]: + if componentstr is not None: + hascomponent = True + + if componentstr.isdigit() is False: + raise ISOFormatError( + '"{0}" is not a valid ISO 8601 date.'.format(isodatestr) + ) + + if hascomponent is False: + raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr)) + + return builder.build_date( + YYYY=yearstr, + MM=monthstr, + DD=daystr, + Www=weekstr, + D=weekdaystr, + DDD=ordinaldaystr, + ) diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/decimalfraction.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/decimalfraction.py new file mode 100644 index 000000000..3086ee794 --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/decimalfraction.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + + +def normalize(value): + """Returns the string with decimal separators normalized.""" + return value.replace(",", ".") diff --git a/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/duration.py b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/duration.py new file mode 100644 index 000000000..cdc0f8f7f --- /dev/null +++ b/BackEndChallenge/myproject/lib/python3.8/site-packages/aniso8601/duration.py @@ -0,0 +1,291 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021, Brandon Nielsen +# All rights reserved. +# +# This software may be modified and distributed under the terms +# of the BSD license. See the LICENSE file for details. + +from aniso8601 import compat +from aniso8601.builders import TupleBuilder +from aniso8601.builders.python import PythonTimeBuilder +from aniso8601.date import parse_date +from aniso8601.decimalfraction import normalize +from aniso8601.exceptions import ISOFormatError +from aniso8601.resolution import DurationResolution +from aniso8601.time import parse_time + + +def get_duration_resolution(isodurationstr): + # Valid string formats are: + # + # PnYnMnDTnHnMnS (or any reduced precision equivalent) + # PnW + # PT