Compare commits
106 Commits
lux-smbus
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6574a724b4 | ||
|
|
bc0abbb985 | ||
|
|
f4d95e2441 | ||
|
|
efcba4cfb0 | ||
|
|
69e145aac6 | ||
|
|
a6e44e6c56 | ||
|
|
a6fa60a40a | ||
|
|
3c792cf286 | ||
|
|
babd6d88dc | ||
|
|
21290682b6 | ||
|
|
bd45b88477 | ||
|
|
6f5c01fccc | ||
|
|
6af5d94b8a | ||
|
|
2cd3ff1e78 | ||
|
|
2afc8c8708 | ||
|
|
e8a6021e3f | ||
|
|
da641cad7f | ||
|
|
75f3a6d1c0 | ||
|
|
06f1f9c10c | ||
|
|
ef0fb8b990 | ||
|
|
d81884eebd | ||
|
|
6dc3db1648 | ||
|
|
fbca31d88a | ||
|
|
852e05d2c2 | ||
|
|
ef90f0e4dc | ||
|
|
5dfbe6f951 | ||
|
|
54618be769 | ||
|
|
721c6ac0a7 | ||
|
|
7e3a4855d8 | ||
|
|
41ae988562 | ||
|
|
8f38cf62ac | ||
|
|
26890a8bbf | ||
|
|
879cb28b9e | ||
|
|
6c37a7b1a9 | ||
|
|
919dd41321 | ||
|
|
017721f659 | ||
|
|
ee0d1184ed | ||
|
|
b4352eb844 | ||
|
|
dddd6e8632 | ||
|
|
548ae2be2c | ||
|
|
209f557a9b | ||
|
|
307972b9ec | ||
|
|
9bd22c5fff | ||
|
|
3f2e729d85 | ||
|
|
c48da832e0 | ||
|
|
659fb74071 | ||
|
|
0035b2e6f3 | ||
|
|
0f58892d85 | ||
|
|
cf8af255c6 | ||
|
|
5391985618 | ||
|
|
a23ecd095c | ||
|
|
ca819b84e7 | ||
|
|
4691b30bf3 | ||
|
|
b37849ddef | ||
|
|
58c79ecbd4 | ||
|
|
888296e3e1 | ||
|
|
863b998eae | ||
|
|
c78ed7323a | ||
|
|
9e69651f0c | ||
|
|
2211f7ca95 | ||
|
|
dc12b92d5b | ||
|
|
559b1f2a7c | ||
|
|
7abc0ec624 | ||
|
|
91ef012688 | ||
|
|
0f5bd9fef4 | ||
|
|
45594aeac0 | ||
|
|
c8b3ab2413 | ||
|
|
52464ec5a8 | ||
|
|
37db23a0e8 | ||
|
|
c4fe5fbf37 | ||
|
|
8072fe9c36 | ||
|
|
2e263f1b14 | ||
|
|
fe07f41425 | ||
|
|
4b7f96a378 | ||
|
|
02ebfd7ce2 | ||
|
|
2e53784002 | ||
|
|
4c35d0f179 | ||
|
|
fc112d997b | ||
|
|
2e4c7e2683 | ||
|
|
fa6675cb04 | ||
|
|
212ea9ec65 | ||
|
|
c92fd63160 | ||
|
|
f8b7306dd0 | ||
|
|
b6f2379a38 | ||
|
|
fc7a1bf167 | ||
|
|
3c55e96341 | ||
|
|
44a636010e | ||
|
|
36d77591f4 | ||
|
|
c4fba54407 | ||
|
|
6c63adcdfb | ||
|
|
46d788aae3 | ||
|
|
8f7f170d6a | ||
|
|
ea28ff7bef | ||
|
|
d1435047e4 | ||
|
|
253ec3a28e | ||
|
|
e3bbab819b | ||
|
|
1ba8f72e09 | ||
|
|
3377554e0d | ||
|
|
e441f4f7f7 | ||
|
|
33f0511081 | ||
|
|
8ee094481c | ||
|
|
d5815fe849 | ||
|
|
f8a05efc31 | ||
|
|
6b2e7f3129 | ||
|
|
65733488f7 | ||
|
|
512f877039 |
BIN
..gitignore.swp
Normal file
BIN
..gitignore.swp
Normal file
Binary file not shown.
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
site/
|
||||
14
LICENSE.txt
Normal file
14
LICENSE.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
Copyright (c) 2018, 2019, Kristjan Komloši, Jakob Kosec, Juš Dolžan,
|
||||
TeraHz development team
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
23
README.md
23
README.md
@@ -1,9 +1,24 @@
|
||||
# TeraHz
|
||||
TeraHz is a low-cost spectrometer.
|
||||
|
||||
|
||||
[](https://terahz.readthedocs.io/en/latest/?badge=latest)
|
||||
|
||||
TeraHz is a low-cost spectrometer based on a Raspberry Pi 3 or 3 B+ and three sensors:
|
||||
+ [__AS7265x__](https://www.tindie.com/products/onehorse/compact-as7265x-spectrometer/)
|
||||
is a 18 channel spectrometer chipset that provides the device with spectral data
|
||||
+ [__VEML6075__](https://www.sparkfun.com/products/15089) is an
|
||||
UVA/UVB sensor
|
||||
+ [__APDS-9301__](https://www.sparkfun.com/products/14350) is a calibrated illuminance (lux) meter that provides the device with reliable readings
|
||||
|
||||
## Why?
|
||||
Because people and institutions could use an affordable and accurate light-analysing device that is also portable, easy to use and simple to assemble. TeraHz was started as an answer to our high school not being able to afford a commercially available solution. One TeraHz spectrometer costs around 150$ in parts, which makes it a competitive alternative to other solutions on the market today.
|
||||
|
||||
## Development team
|
||||
Copyright 2018, 2019
|
||||
|
||||
- Kristjan "d3m1g0d" Komloši (electronics engineer, middleware)
|
||||
- Juš "ANormalPerson" Dolžan (backend developer)
|
||||
- Jakob "D3m1j4ck" Kosec (frontend developer)
|
||||
- Kristjan "cls-02" Komloši (electronics, sensor drivers, backend)
|
||||
- Jakob "D3m1j4ck" Kosec (frontend)
|
||||
|
||||
|
||||
I would also like to thank Juš "ANormalPerson" Dolžan, who decided to leave the
|
||||
team, but helped me a lot with backend development.
|
||||
|
||||
BIN
backend/__pycache__/main.cpython-35.pyc
Normal file
BIN
backend/__pycache__/main.cpython-35.pyc
Normal file
Binary file not shown.
BIN
backend/__pycache__/main.cpython-37.pyc
Normal file
BIN
backend/__pycache__/main.cpython-37.pyc
Normal file
Binary file not shown.
BIN
backend/__pycache__/sensors.cpython-35.pyc
Normal file
BIN
backend/__pycache__/sensors.cpython-35.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
backend/__pycache__/sensors.cpython-37.pyc
Normal file
BIN
backend/__pycache__/sensors.cpython-37.pyc
Normal file
Binary file not shown.
BIN
backend/__pycache__/storage.cpython-37.pyc
Normal file
BIN
backend/__pycache__/storage.cpython-37.pyc
Normal file
Binary file not shown.
16
backend/app.py
Normal file
16
backend/app.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# app.py - main backend program
|
||||
# All code in this file is licensed under the ISC license, provided in LICENSE.txt
|
||||
from flask import Flask, redirect, url_for, request
|
||||
import flask
|
||||
import sensors
|
||||
import json
|
||||
app = Flask(__name__)
|
||||
s=sensors.Spectrometer(path='/dev/serial0', baudrate=115200, tout=1)
|
||||
u=sensors.UVSensor()
|
||||
l=sensors.LxMeter()
|
||||
|
||||
@app.route('/data')
|
||||
def sendData():
|
||||
response = flask.jsonify([s.getData(), l.getData(), u.getABI()])
|
||||
response.headers.add('Access-Control-Allow-Origin', '*')
|
||||
return response
|
||||
BIN
backend/main.pyc
Normal file
BIN
backend/main.pyc
Normal file
Binary file not shown.
BIN
backend/sample.db
Normal file
BIN
backend/sample.db
Normal file
Binary file not shown.
@@ -1,7 +1,6 @@
|
||||
# sensors.py - a module for interfacing to the sensors
|
||||
# Copyright 2019 Kristjan Komloši
|
||||
# The code in this file is licensed under the 3-clause BSD License
|
||||
|
||||
# All code in this file is licensed under the ISC license, provided in LICENSE.txt
|
||||
import serial as ser
|
||||
import pandas as pd
|
||||
import smbus2
|
||||
@@ -24,27 +23,26 @@ class Spectrometer:
|
||||
except:
|
||||
raise Exception('An exception ocurred when performing spectrometer handshake')
|
||||
ex(1)
|
||||
self.setParameters()
|
||||
|
||||
def setParameters(self):
|
||||
def setParameters(self, parameters):
|
||||
'''applies the parameters like LED light and gain to the spectrometer'''
|
||||
try:
|
||||
if 'it_time' in self.parameters:
|
||||
it_time = int(self.parameters['it_time'])
|
||||
if 'it_time' in parameters:
|
||||
it_time = int(parameters['it_time'])
|
||||
if it_time <=0 :
|
||||
it_time = 1
|
||||
self.serialObject.write('ATINTTIME={}\n'.format(string(it_time)).encode())
|
||||
self.serialObject.readline()
|
||||
|
||||
if 'gain' in self.parameters:
|
||||
gain = int(self.parameters['gain'])
|
||||
if 'gain' in parameters:
|
||||
gain = int(parameters['gain'])
|
||||
if gain < 0 or gain > 3:
|
||||
gain = 1
|
||||
self.serialObject.write('ATGAIN={}\n'.format(gain).encode())
|
||||
self.serialObject.readline()
|
||||
|
||||
if 'led' in self.parameters:
|
||||
led = bool(self.parameters['led'])
|
||||
if 'led' in parameters:
|
||||
led = bool(parameters['led'])
|
||||
if led:
|
||||
led=1
|
||||
else:
|
||||
@@ -55,7 +53,7 @@ class Spectrometer:
|
||||
raise Exception('An exception occured during spectrometer initialization')
|
||||
ex(1)
|
||||
|
||||
def refreshData(self):
|
||||
def getData(self):
|
||||
try:
|
||||
self.serialObject.write(b'ATCDATA\n')
|
||||
rawresp = self.serialObject.readline().decode()
|
||||
@@ -66,14 +64,13 @@ class Spectrometer:
|
||||
responseorder = [i for i in 'RSTUVWGHIJKLABCDEF']
|
||||
realorder = [i for i in 'ABCDEFGHRISJTUVWKL']
|
||||
response = pd.Series([float(i)/35.0 for i in rawresp[:-3].split(',')], index=responseorder)
|
||||
self.data = pd.DataFrame(response, index=realorder, columns = ['uW/cm^2'])
|
||||
return pd.DataFrame(response, index=realorder, columns = ['uW/cm^2']).to_dict()['uW/cm^2']
|
||||
|
||||
|
||||
def __init__(self, path='/dev/ttyUSB0', baudrate=115200, tout=1, rrate=1, params={}):
|
||||
def __init__(self, path='/dev/ttyUSB0', baudrate=115200, tout=1):
|
||||
self.path = path
|
||||
self.baudrate = baudrate
|
||||
self.timeout = 1
|
||||
self.parameters = params
|
||||
try:
|
||||
self.serialObject = ser.Serial(path, baudrate, timeout=tout)
|
||||
except:
|
||||
@@ -81,7 +78,6 @@ class Spectrometer:
|
||||
ex(1)
|
||||
else:
|
||||
self.initializeSensor()
|
||||
self.startDataCollection()
|
||||
|
||||
|
||||
class LxMeter:
|
||||
@@ -94,7 +90,7 @@ class LxMeter:
|
||||
|
||||
try:
|
||||
self.bus.write_byte_data(self.addr, 0xa0, 0x03) # enable the sensor
|
||||
setGain(16)
|
||||
self.setGain(16)
|
||||
except:
|
||||
raise Exception('An exception occured when enabling lux meter')
|
||||
|
||||
@@ -133,14 +129,14 @@ class LxMeter:
|
||||
temp = self.bus.read_byte_data(self.addr, 0xa1)
|
||||
self.bus.write_byte_data(self.addr, 0xa1, (temp & 0xfc) | time)
|
||||
except:
|
||||
raise Exception('An error occured setting lux integration time')
|
||||
raise Exception('An exception occured setting lux integration time')
|
||||
|
||||
def getIntTime(self):
|
||||
'''Get the lux sensor integration time.'''
|
||||
try:
|
||||
return self.bus.read_byte_data(self.addr, 0xa1) & 0xfc
|
||||
return self.bus.read_byte_data(self.addr, 0xa1) & 0x03
|
||||
except:
|
||||
raise Exception('An error occured getting lux integration time')
|
||||
raise Exception('An exception occured getting lux integration time')
|
||||
|
||||
def getData(self):
|
||||
'''return the calculated lux value'''
|
||||
@@ -148,16 +144,86 @@ class LxMeter:
|
||||
chA = self.bus.read_word_data(self.addr, 0xac)
|
||||
chB = self.bus.read_word_data(self.addr, 0xae)
|
||||
except:
|
||||
raise Exception('An error occured fetching lux channels')
|
||||
raise Exception('An exception occured fetching lux channels')
|
||||
|
||||
# scary computations ahead! refer to the apds-9301 datasheet!
|
||||
if chB/chA <= 0.5 and chB/chA > 0:
|
||||
lux = (0.0304*chA) - (0.062*chA*((chB/chA)**1.4))
|
||||
lux = 0.0304*chA - 0.062*chA*(chB/chA)**1.4
|
||||
elif chB/chA <= 0.61 and chB/chA > 0.5:
|
||||
lux = (0.0224*chA) - (0.031*chB)
|
||||
lux = 0.0224*chA - 0.031*chB
|
||||
elif chB/chA <=0.8 and chB/chA > 0.61:
|
||||
lux = (0.0128*chA) - (0.0153*chB)
|
||||
lux = 0.0128*chA - 0.0153*chB
|
||||
elif chB/chA <=1.3 and chB/chA >0.8:
|
||||
lux = (0.00146*chA) - (0.00112*chB)
|
||||
lux = 0.00146*chA - 0.00112*chB
|
||||
else:
|
||||
lux = 0
|
||||
return lux
|
||||
|
||||
class UVSensor:
|
||||
def __init__(self, bus=1, addr=0x10):
|
||||
self.addr=addr
|
||||
try:
|
||||
self.bus = smbus2.SMBus(bus)
|
||||
except:
|
||||
raise Exception('An exception occured opening SMBus {}'.format(bus))
|
||||
|
||||
try:
|
||||
# enable the sensor and set the integration time
|
||||
self.bus.write_byte_data(self.addr, 0x00, 0b00010000)
|
||||
except:
|
||||
raise Exception('An exception occured when initalizing the UV Sensor')
|
||||
|
||||
def getABI(self):
|
||||
'''Calculates the UVA and UVB irradiances,
|
||||
along with UV index. Returns [a,b,i]'''
|
||||
|
||||
try:
|
||||
# read the raw UVA, UVB and compensation values from the sensor
|
||||
aRaw = self.bus.read_word_data(self.addr, 0x07)
|
||||
bRaw = self.bus.read_word_data(self.addr, 0x09)
|
||||
c1 = self.bus.read_word_data(self.addr, 0x0a)
|
||||
c2 = self.bus.read_word_data(self.addr, 0x0b)
|
||||
except:
|
||||
raise Exception('An exception occured when fetching raw UV data')
|
||||
# scary computations ahead! refer to Vishay app note 84339 and Sparkfun
|
||||
# VEML6075 documentation.
|
||||
|
||||
# first, compensate for visible and IR noise
|
||||
aCorr = aRaw - 2.22 * c1 - 1.33 * c2
|
||||
bCorr = bRaw - 2.95 * c1 - 1.74 * c2
|
||||
|
||||
# second, convert values into irradiances
|
||||
a = aCorr * 0.00110
|
||||
b = bCorr * 0.00125
|
||||
|
||||
# last, calculate the UV index
|
||||
i = (a + b) / 2
|
||||
|
||||
return [a,b,i]
|
||||
|
||||
def getA(self):
|
||||
return self.getABI()[0]
|
||||
|
||||
def getB(self):
|
||||
return self.getABI()[1]
|
||||
|
||||
def getI(self):
|
||||
return self.getABI()[2]
|
||||
|
||||
def on(self):
|
||||
'''Turns the UV sensor on after shutdown.'''
|
||||
try:
|
||||
# write the default value for power on
|
||||
# no configurable params = no bitmask
|
||||
self.bus.write_byte_data(self.addr, 0x00, 0x10)
|
||||
except:
|
||||
raise Exception('An exception occured when turning the UV sensor on')
|
||||
|
||||
def off(self):
|
||||
'''Shuts the UV sensor down.'''
|
||||
try:
|
||||
# write the default value + the shutdown bit
|
||||
# no configurable params = no bitmask
|
||||
self.bus.write_byte_data(self.addr, 0x00, 0x11)
|
||||
except:
|
||||
raise Exception('An exception occured when shutting the UV sensor down')
|
||||
|
||||
31
backend/storage.py
Normal file
31
backend/storage.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# storage.py - storage backend for TeraHz
|
||||
# Copyright Kristjan Komloši 2019
|
||||
# All code in this file is licensed under the ISC license, provided in LICENSE.txt
|
||||
|
||||
|
||||
import sqlite3
|
||||
class jsonStorage:
|
||||
def __init__(self, dbFile):
|
||||
'''Storage object constructor. Argument is filename'''
|
||||
self.db = sqlite3.connect(dbFile)
|
||||
|
||||
def listJSONs(self):
|
||||
c = self.db.cursor()
|
||||
c.execute('SELECT * FROM storage')
|
||||
result = c.fetchall()
|
||||
c.close()
|
||||
return result
|
||||
|
||||
def storeJSON(self, jsonString, comment):
|
||||
c = self.db.cursor()
|
||||
c.execute('INSERT INTO storage VALUES (datetime(\'now\', \'localtime\'), ?, ?)', (comment, jsonString))
|
||||
c.close()
|
||||
self.db.commit()
|
||||
|
||||
def retrieveJSON(self, timestamp):
|
||||
'''Retrieves a JSON entry. Takes a timestamp string'''
|
||||
c = self.db.cursor()
|
||||
c.execute('SELECT * FROM storage WHERE timestamp = ?', (timestamp,))
|
||||
result = c.fetchall()
|
||||
c.close()
|
||||
return result
|
||||
Binary file not shown.
@@ -1,76 +0,0 @@
|
||||
# This file must be used with "source bin/activate" *from bash*
|
||||
# you cannot run it directly
|
||||
|
||||
deactivate () {
|
||||
# reset old environment variables
|
||||
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
|
||||
PATH="${_OLD_VIRTUAL_PATH:-}"
|
||||
export PATH
|
||||
unset _OLD_VIRTUAL_PATH
|
||||
fi
|
||||
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
|
||||
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
|
||||
export PYTHONHOME
|
||||
unset _OLD_VIRTUAL_PYTHONHOME
|
||||
fi
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
|
||||
hash -r
|
||||
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="/root/projekti/TeraHz/backend/venv"
|
||||
export VIRTUAL_ENV
|
||||
|
||||
_OLD_VIRTUAL_PATH="$PATH"
|
||||
PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||
export PATH
|
||||
|
||||
# unset PYTHONHOME if set
|
||||
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
|
||||
# could use `if (set -u; : $PYTHONHOME) ;` in bash
|
||||
if [ -n "${PYTHONHOME:-}" ] ; then
|
||||
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
|
||||
unset PYTHONHOME
|
||||
fi
|
||||
|
||||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
|
||||
_OLD_VIRTUAL_PS1="${PS1:-}"
|
||||
if [ "x(venv) " != x ] ; then
|
||||
PS1="(venv) ${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
|
||||
@@ -1,37 +0,0 @@
|
||||
# This file must be used with "source bin/activate.csh" *from csh*.
|
||||
# You cannot run it directly.
|
||||
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
||||
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
|
||||
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
setenv VIRTUAL_ENV "/root/projekti/TeraHz/backend/venv"
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH"
|
||||
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
|
||||
|
||||
|
||||
set _OLD_VIRTUAL_PROMPT="$prompt"
|
||||
|
||||
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
|
||||
if ("venv" != "") then
|
||||
set env_name = "venv"
|
||||
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
|
||||
@@ -1,75 +0,0 @@
|
||||
# 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 "/root/projekti/TeraHz/backend/venv"
|
||||
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
|
||||
|
||||
# unset PYTHONHOME if set
|
||||
if set -q PYTHONHOME
|
||||
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
|
||||
set -e PYTHONHOME
|
||||
end
|
||||
|
||||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
|
||||
# fish uses a function instead of an env var to generate the prompt.
|
||||
|
||||
# save the current fish_prompt function as the function _old_fish_prompt
|
||||
functions -c fish_prompt _old_fish_prompt
|
||||
|
||||
# with the original prompt function renamed, we can override with our own.
|
||||
function fish_prompt
|
||||
# Save the return status of the last command
|
||||
set -l old_status $status
|
||||
|
||||
# Prompt override?
|
||||
if test -n "(venv) "
|
||||
printf "%s%s" "(venv) " (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
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from setuptools.command.easy_install import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from setuptools.command.easy_install import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from numpy.f2py.f2py2e import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from numpy.f2py.f2py2e import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from numpy.f2py.f2py2e import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from flask.cli import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'future==0.17.1','console_scripts','futurize'
|
||||
__requires__ = 'future==0.17.1'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('future==0.17.1', 'console_scripts', 'futurize')()
|
||||
)
|
||||
@@ -1,976 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
#
|
||||
# Very simple serial terminal
|
||||
#
|
||||
# This file is part of pySerial. https://github.com/pyserial/pyserial
|
||||
# (C)2002-2015 Chris Liechti <cliechti@gmx.net>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import codecs
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
|
||||
import serial
|
||||
from serial.tools.list_ports import comports
|
||||
from serial.tools import hexlify_codec
|
||||
|
||||
# pylint: disable=wrong-import-order,wrong-import-position
|
||||
|
||||
codecs.register(lambda c: hexlify_codec.getregentry() if c == 'hexlify' else None)
|
||||
|
||||
try:
|
||||
raw_input
|
||||
except NameError:
|
||||
# pylint: disable=redefined-builtin,invalid-name
|
||||
raw_input = input # in python3 it's "raw"
|
||||
unichr = chr
|
||||
|
||||
|
||||
def key_description(character):
|
||||
"""generate a readable description for a key"""
|
||||
ascii_code = ord(character)
|
||||
if ascii_code < 32:
|
||||
return 'Ctrl+{:c}'.format(ord('@') + ascii_code)
|
||||
else:
|
||||
return repr(character)
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
class ConsoleBase(object):
|
||||
"""OS abstraction for console (input/output codec, no echo)"""
|
||||
|
||||
def __init__(self):
|
||||
if sys.version_info >= (3, 0):
|
||||
self.byte_output = sys.stdout.buffer
|
||||
else:
|
||||
self.byte_output = sys.stdout
|
||||
self.output = sys.stdout
|
||||
|
||||
def setup(self):
|
||||
"""Set console to read single characters, no echo"""
|
||||
|
||||
def cleanup(self):
|
||||
"""Restore default console settings"""
|
||||
|
||||
def getkey(self):
|
||||
"""Read a single key from the console"""
|
||||
return None
|
||||
|
||||
def write_bytes(self, byte_string):
|
||||
"""Write bytes (already encoded)"""
|
||||
self.byte_output.write(byte_string)
|
||||
self.byte_output.flush()
|
||||
|
||||
def write(self, text):
|
||||
"""Write string"""
|
||||
self.output.write(text)
|
||||
self.output.flush()
|
||||
|
||||
def cancel(self):
|
||||
"""Cancel getkey operation"""
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# context manager:
|
||||
# switch terminal temporary to normal mode (e.g. to get user input)
|
||||
|
||||
def __enter__(self):
|
||||
self.cleanup()
|
||||
return self
|
||||
|
||||
def __exit__(self, *args, **kwargs):
|
||||
self.setup()
|
||||
|
||||
|
||||
if os.name == 'nt': # noqa
|
||||
import msvcrt
|
||||
import ctypes
|
||||
|
||||
class Out(object):
|
||||
"""file-like wrapper that uses os.write"""
|
||||
|
||||
def __init__(self, fd):
|
||||
self.fd = fd
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def write(self, s):
|
||||
os.write(self.fd, s)
|
||||
|
||||
class Console(ConsoleBase):
|
||||
def __init__(self):
|
||||
super(Console, self).__init__()
|
||||
self._saved_ocp = ctypes.windll.kernel32.GetConsoleOutputCP()
|
||||
self._saved_icp = ctypes.windll.kernel32.GetConsoleCP()
|
||||
ctypes.windll.kernel32.SetConsoleOutputCP(65001)
|
||||
ctypes.windll.kernel32.SetConsoleCP(65001)
|
||||
self.output = codecs.getwriter('UTF-8')(Out(sys.stdout.fileno()), 'replace')
|
||||
# the change of the code page is not propagated to Python, manually fix it
|
||||
sys.stderr = codecs.getwriter('UTF-8')(Out(sys.stderr.fileno()), 'replace')
|
||||
sys.stdout = self.output
|
||||
self.output.encoding = 'UTF-8' # needed for input
|
||||
|
||||
def __del__(self):
|
||||
ctypes.windll.kernel32.SetConsoleOutputCP(self._saved_ocp)
|
||||
ctypes.windll.kernel32.SetConsoleCP(self._saved_icp)
|
||||
|
||||
def getkey(self):
|
||||
while True:
|
||||
z = msvcrt.getwch()
|
||||
if z == unichr(13):
|
||||
return unichr(10)
|
||||
elif z in (unichr(0), unichr(0x0e)): # functions keys, ignore
|
||||
msvcrt.getwch()
|
||||
else:
|
||||
return z
|
||||
|
||||
def cancel(self):
|
||||
# CancelIo, CancelSynchronousIo do not seem to work when using
|
||||
# getwch, so instead, send a key to the window with the console
|
||||
hwnd = ctypes.windll.kernel32.GetConsoleWindow()
|
||||
ctypes.windll.user32.PostMessageA(hwnd, 0x100, 0x0d, 0)
|
||||
|
||||
elif os.name == 'posix':
|
||||
import atexit
|
||||
import termios
|
||||
import fcntl
|
||||
|
||||
class Console(ConsoleBase):
|
||||
def __init__(self):
|
||||
super(Console, self).__init__()
|
||||
self.fd = sys.stdin.fileno()
|
||||
self.old = termios.tcgetattr(self.fd)
|
||||
atexit.register(self.cleanup)
|
||||
if sys.version_info < (3, 0):
|
||||
self.enc_stdin = codecs.getreader(sys.stdin.encoding)(sys.stdin)
|
||||
else:
|
||||
self.enc_stdin = sys.stdin
|
||||
|
||||
def setup(self):
|
||||
new = termios.tcgetattr(self.fd)
|
||||
new[3] = new[3] & ~termios.ICANON & ~termios.ECHO & ~termios.ISIG
|
||||
new[6][termios.VMIN] = 1
|
||||
new[6][termios.VTIME] = 0
|
||||
termios.tcsetattr(self.fd, termios.TCSANOW, new)
|
||||
|
||||
def getkey(self):
|
||||
c = self.enc_stdin.read(1)
|
||||
if c == unichr(0x7f):
|
||||
c = unichr(8) # map the BS key (which yields DEL) to backspace
|
||||
return c
|
||||
|
||||
def cancel(self):
|
||||
fcntl.ioctl(self.fd, termios.TIOCSTI, b'\0')
|
||||
|
||||
def cleanup(self):
|
||||
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old)
|
||||
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
'Sorry no implementation for your platform ({}) available.'.format(sys.platform))
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
class Transform(object):
|
||||
"""do-nothing: forward all data unchanged"""
|
||||
def rx(self, text):
|
||||
"""text received from serial port"""
|
||||
return text
|
||||
|
||||
def tx(self, text):
|
||||
"""text to be sent to serial port"""
|
||||
return text
|
||||
|
||||
def echo(self, text):
|
||||
"""text to be sent but displayed on console"""
|
||||
return text
|
||||
|
||||
|
||||
class CRLF(Transform):
|
||||
"""ENTER sends CR+LF"""
|
||||
|
||||
def tx(self, text):
|
||||
return text.replace('\n', '\r\n')
|
||||
|
||||
|
||||
class CR(Transform):
|
||||
"""ENTER sends CR"""
|
||||
|
||||
def rx(self, text):
|
||||
return text.replace('\r', '\n')
|
||||
|
||||
def tx(self, text):
|
||||
return text.replace('\n', '\r')
|
||||
|
||||
|
||||
class LF(Transform):
|
||||
"""ENTER sends LF"""
|
||||
|
||||
|
||||
class NoTerminal(Transform):
|
||||
"""remove typical terminal control codes from input"""
|
||||
|
||||
REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32) if unichr(x) not in '\r\n\b\t')
|
||||
REPLACEMENT_MAP.update(
|
||||
{
|
||||
0x7F: 0x2421, # DEL
|
||||
0x9B: 0x2425, # CSI
|
||||
})
|
||||
|
||||
def rx(self, text):
|
||||
return text.translate(self.REPLACEMENT_MAP)
|
||||
|
||||
echo = rx
|
||||
|
||||
|
||||
class NoControls(NoTerminal):
|
||||
"""Remove all control codes, incl. CR+LF"""
|
||||
|
||||
REPLACEMENT_MAP = dict((x, 0x2400 + x) for x in range(32))
|
||||
REPLACEMENT_MAP.update(
|
||||
{
|
||||
0x20: 0x2423, # visual space
|
||||
0x7F: 0x2421, # DEL
|
||||
0x9B: 0x2425, # CSI
|
||||
})
|
||||
|
||||
|
||||
class Printable(Transform):
|
||||
"""Show decimal code for all non-ASCII characters and replace most control codes"""
|
||||
|
||||
def rx(self, text):
|
||||
r = []
|
||||
for c in text:
|
||||
if ' ' <= c < '\x7f' or c in '\r\n\b\t':
|
||||
r.append(c)
|
||||
elif c < ' ':
|
||||
r.append(unichr(0x2400 + ord(c)))
|
||||
else:
|
||||
r.extend(unichr(0x2080 + ord(d) - 48) for d in '{:d}'.format(ord(c)))
|
||||
r.append(' ')
|
||||
return ''.join(r)
|
||||
|
||||
echo = rx
|
||||
|
||||
|
||||
class Colorize(Transform):
|
||||
"""Apply different colors for received and echo"""
|
||||
|
||||
def __init__(self):
|
||||
# XXX make it configurable, use colorama?
|
||||
self.input_color = '\x1b[37m'
|
||||
self.echo_color = '\x1b[31m'
|
||||
|
||||
def rx(self, text):
|
||||
return self.input_color + text
|
||||
|
||||
def echo(self, text):
|
||||
return self.echo_color + text
|
||||
|
||||
|
||||
class DebugIO(Transform):
|
||||
"""Print what is sent and received"""
|
||||
|
||||
def rx(self, text):
|
||||
sys.stderr.write(' [RX:{}] '.format(repr(text)))
|
||||
sys.stderr.flush()
|
||||
return text
|
||||
|
||||
def tx(self, text):
|
||||
sys.stderr.write(' [TX:{}] '.format(repr(text)))
|
||||
sys.stderr.flush()
|
||||
return text
|
||||
|
||||
|
||||
# other ideas:
|
||||
# - add date/time for each newline
|
||||
# - insert newline after: a) timeout b) packet end character
|
||||
|
||||
EOL_TRANSFORMATIONS = {
|
||||
'crlf': CRLF,
|
||||
'cr': CR,
|
||||
'lf': LF,
|
||||
}
|
||||
|
||||
TRANSFORMATIONS = {
|
||||
'direct': Transform, # no transformation
|
||||
'default': NoTerminal,
|
||||
'nocontrol': NoControls,
|
||||
'printable': Printable,
|
||||
'colorize': Colorize,
|
||||
'debug': DebugIO,
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
def ask_for_port():
|
||||
"""\
|
||||
Show a list of ports and ask the user for a choice. To make selection
|
||||
easier on systems with long device names, also allow the input of an
|
||||
index.
|
||||
"""
|
||||
sys.stderr.write('\n--- Available ports:\n')
|
||||
ports = []
|
||||
for n, (port, desc, hwid) in enumerate(sorted(comports()), 1):
|
||||
sys.stderr.write('--- {:2}: {:20} {!r}\n'.format(n, port, desc))
|
||||
ports.append(port)
|
||||
while True:
|
||||
port = raw_input('--- Enter port index or full name: ')
|
||||
try:
|
||||
index = int(port) - 1
|
||||
if not 0 <= index < len(ports):
|
||||
sys.stderr.write('--- Invalid index!\n')
|
||||
continue
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
port = ports[index]
|
||||
return port
|
||||
|
||||
|
||||
class Miniterm(object):
|
||||
"""\
|
||||
Terminal application. Copy data from serial port to console and vice versa.
|
||||
Handle special keys from the console to show menu etc.
|
||||
"""
|
||||
|
||||
def __init__(self, serial_instance, echo=False, eol='crlf', filters=()):
|
||||
self.console = Console()
|
||||
self.serial = serial_instance
|
||||
self.echo = echo
|
||||
self.raw = False
|
||||
self.input_encoding = 'UTF-8'
|
||||
self.output_encoding = 'UTF-8'
|
||||
self.eol = eol
|
||||
self.filters = filters
|
||||
self.update_transformations()
|
||||
self.exit_character = 0x1d # GS/CTRL+]
|
||||
self.menu_character = 0x14 # Menu: CTRL+T
|
||||
self.alive = None
|
||||
self._reader_alive = None
|
||||
self.receiver_thread = None
|
||||
self.rx_decoder = None
|
||||
self.tx_decoder = None
|
||||
|
||||
def _start_reader(self):
|
||||
"""Start reader thread"""
|
||||
self._reader_alive = True
|
||||
# start serial->console thread
|
||||
self.receiver_thread = threading.Thread(target=self.reader, name='rx')
|
||||
self.receiver_thread.daemon = True
|
||||
self.receiver_thread.start()
|
||||
|
||||
def _stop_reader(self):
|
||||
"""Stop reader thread only, wait for clean exit of thread"""
|
||||
self._reader_alive = False
|
||||
if hasattr(self.serial, 'cancel_read'):
|
||||
self.serial.cancel_read()
|
||||
self.receiver_thread.join()
|
||||
|
||||
def start(self):
|
||||
"""start worker threads"""
|
||||
self.alive = True
|
||||
self._start_reader()
|
||||
# enter console->serial loop
|
||||
self.transmitter_thread = threading.Thread(target=self.writer, name='tx')
|
||||
self.transmitter_thread.daemon = True
|
||||
self.transmitter_thread.start()
|
||||
self.console.setup()
|
||||
|
||||
def stop(self):
|
||||
"""set flag to stop worker threads"""
|
||||
self.alive = False
|
||||
|
||||
def join(self, transmit_only=False):
|
||||
"""wait for worker threads to terminate"""
|
||||
self.transmitter_thread.join()
|
||||
if not transmit_only:
|
||||
if hasattr(self.serial, 'cancel_read'):
|
||||
self.serial.cancel_read()
|
||||
self.receiver_thread.join()
|
||||
|
||||
def close(self):
|
||||
self.serial.close()
|
||||
|
||||
def update_transformations(self):
|
||||
"""take list of transformation classes and instantiate them for rx and tx"""
|
||||
transformations = [EOL_TRANSFORMATIONS[self.eol]] + [TRANSFORMATIONS[f]
|
||||
for f in self.filters]
|
||||
self.tx_transformations = [t() for t in transformations]
|
||||
self.rx_transformations = list(reversed(self.tx_transformations))
|
||||
|
||||
def set_rx_encoding(self, encoding, errors='replace'):
|
||||
"""set encoding for received data"""
|
||||
self.input_encoding = encoding
|
||||
self.rx_decoder = codecs.getincrementaldecoder(encoding)(errors)
|
||||
|
||||
def set_tx_encoding(self, encoding, errors='replace'):
|
||||
"""set encoding for transmitted data"""
|
||||
self.output_encoding = encoding
|
||||
self.tx_encoder = codecs.getincrementalencoder(encoding)(errors)
|
||||
|
||||
def dump_port_settings(self):
|
||||
"""Write current settings to sys.stderr"""
|
||||
sys.stderr.write("\n--- Settings: {p.name} {p.baudrate},{p.bytesize},{p.parity},{p.stopbits}\n".format(
|
||||
p=self.serial))
|
||||
sys.stderr.write('--- RTS: {:8} DTR: {:8} BREAK: {:8}\n'.format(
|
||||
('active' if self.serial.rts else 'inactive'),
|
||||
('active' if self.serial.dtr else 'inactive'),
|
||||
('active' if self.serial.break_condition else 'inactive')))
|
||||
try:
|
||||
sys.stderr.write('--- CTS: {:8} DSR: {:8} RI: {:8} CD: {:8}\n'.format(
|
||||
('active' if self.serial.cts else 'inactive'),
|
||||
('active' if self.serial.dsr else 'inactive'),
|
||||
('active' if self.serial.ri else 'inactive'),
|
||||
('active' if self.serial.cd else 'inactive')))
|
||||
except serial.SerialException:
|
||||
# on RFC 2217 ports, it can happen if no modem state notification was
|
||||
# yet received. ignore this error.
|
||||
pass
|
||||
sys.stderr.write('--- software flow control: {}\n'.format('active' if self.serial.xonxoff else 'inactive'))
|
||||
sys.stderr.write('--- hardware flow control: {}\n'.format('active' if self.serial.rtscts else 'inactive'))
|
||||
sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding))
|
||||
sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding))
|
||||
sys.stderr.write('--- EOL: {}\n'.format(self.eol.upper()))
|
||||
sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters)))
|
||||
|
||||
def reader(self):
|
||||
"""loop and copy serial->console"""
|
||||
try:
|
||||
while self.alive and self._reader_alive:
|
||||
# read all that is there or wait for one byte
|
||||
data = self.serial.read(self.serial.in_waiting or 1)
|
||||
if data:
|
||||
if self.raw:
|
||||
self.console.write_bytes(data)
|
||||
else:
|
||||
text = self.rx_decoder.decode(data)
|
||||
for transformation in self.rx_transformations:
|
||||
text = transformation.rx(text)
|
||||
self.console.write(text)
|
||||
except serial.SerialException:
|
||||
self.alive = False
|
||||
self.console.cancel()
|
||||
raise # XXX handle instead of re-raise?
|
||||
|
||||
def writer(self):
|
||||
"""\
|
||||
Loop and copy console->serial until self.exit_character character is
|
||||
found. When self.menu_character is found, interpret the next key
|
||||
locally.
|
||||
"""
|
||||
menu_active = False
|
||||
try:
|
||||
while self.alive:
|
||||
try:
|
||||
c = self.console.getkey()
|
||||
except KeyboardInterrupt:
|
||||
c = '\x03'
|
||||
if not self.alive:
|
||||
break
|
||||
if menu_active:
|
||||
self.handle_menu_key(c)
|
||||
menu_active = False
|
||||
elif c == self.menu_character:
|
||||
menu_active = True # next char will be for menu
|
||||
elif c == self.exit_character:
|
||||
self.stop() # exit app
|
||||
break
|
||||
else:
|
||||
#~ if self.raw:
|
||||
text = c
|
||||
for transformation in self.tx_transformations:
|
||||
text = transformation.tx(text)
|
||||
self.serial.write(self.tx_encoder.encode(text))
|
||||
if self.echo:
|
||||
echo_text = c
|
||||
for transformation in self.tx_transformations:
|
||||
echo_text = transformation.echo(echo_text)
|
||||
self.console.write(echo_text)
|
||||
except:
|
||||
self.alive = False
|
||||
raise
|
||||
|
||||
def handle_menu_key(self, c):
|
||||
"""Implement a simple menu / settings"""
|
||||
if c == self.menu_character or c == self.exit_character:
|
||||
# Menu/exit character again -> send itself
|
||||
self.serial.write(self.tx_encoder.encode(c))
|
||||
if self.echo:
|
||||
self.console.write(c)
|
||||
elif c == '\x15': # CTRL+U -> upload file
|
||||
self.upload_file()
|
||||
elif c in '\x08hH?': # CTRL+H, h, H, ? -> Show help
|
||||
sys.stderr.write(self.get_help_text())
|
||||
elif c == '\x12': # CTRL+R -> Toggle RTS
|
||||
self.serial.rts = not self.serial.rts
|
||||
sys.stderr.write('--- RTS {} ---\n'.format('active' if self.serial.rts else 'inactive'))
|
||||
elif c == '\x04': # CTRL+D -> Toggle DTR
|
||||
self.serial.dtr = not self.serial.dtr
|
||||
sys.stderr.write('--- DTR {} ---\n'.format('active' if self.serial.dtr else 'inactive'))
|
||||
elif c == '\x02': # CTRL+B -> toggle BREAK condition
|
||||
self.serial.break_condition = not self.serial.break_condition
|
||||
sys.stderr.write('--- BREAK {} ---\n'.format('active' if self.serial.break_condition else 'inactive'))
|
||||
elif c == '\x05': # CTRL+E -> toggle local echo
|
||||
self.echo = not self.echo
|
||||
sys.stderr.write('--- local echo {} ---\n'.format('active' if self.echo else 'inactive'))
|
||||
elif c == '\x06': # CTRL+F -> edit filters
|
||||
self.change_filter()
|
||||
elif c == '\x0c': # CTRL+L -> EOL mode
|
||||
modes = list(EOL_TRANSFORMATIONS) # keys
|
||||
eol = modes.index(self.eol) + 1
|
||||
if eol >= len(modes):
|
||||
eol = 0
|
||||
self.eol = modes[eol]
|
||||
sys.stderr.write('--- EOL: {} ---\n'.format(self.eol.upper()))
|
||||
self.update_transformations()
|
||||
elif c == '\x01': # CTRL+A -> set encoding
|
||||
self.change_encoding()
|
||||
elif c == '\x09': # CTRL+I -> info
|
||||
self.dump_port_settings()
|
||||
#~ elif c == '\x01': # CTRL+A -> cycle escape mode
|
||||
#~ elif c == '\x0c': # CTRL+L -> cycle linefeed mode
|
||||
elif c in 'pP': # P -> change port
|
||||
self.change_port()
|
||||
elif c in 'sS': # S -> suspend / open port temporarily
|
||||
self.suspend_port()
|
||||
elif c in 'bB': # B -> change baudrate
|
||||
self.change_baudrate()
|
||||
elif c == '8': # 8 -> change to 8 bits
|
||||
self.serial.bytesize = serial.EIGHTBITS
|
||||
self.dump_port_settings()
|
||||
elif c == '7': # 7 -> change to 8 bits
|
||||
self.serial.bytesize = serial.SEVENBITS
|
||||
self.dump_port_settings()
|
||||
elif c in 'eE': # E -> change to even parity
|
||||
self.serial.parity = serial.PARITY_EVEN
|
||||
self.dump_port_settings()
|
||||
elif c in 'oO': # O -> change to odd parity
|
||||
self.serial.parity = serial.PARITY_ODD
|
||||
self.dump_port_settings()
|
||||
elif c in 'mM': # M -> change to mark parity
|
||||
self.serial.parity = serial.PARITY_MARK
|
||||
self.dump_port_settings()
|
||||
elif c in 'sS': # S -> change to space parity
|
||||
self.serial.parity = serial.PARITY_SPACE
|
||||
self.dump_port_settings()
|
||||
elif c in 'nN': # N -> change to no parity
|
||||
self.serial.parity = serial.PARITY_NONE
|
||||
self.dump_port_settings()
|
||||
elif c == '1': # 1 -> change to 1 stop bits
|
||||
self.serial.stopbits = serial.STOPBITS_ONE
|
||||
self.dump_port_settings()
|
||||
elif c == '2': # 2 -> change to 2 stop bits
|
||||
self.serial.stopbits = serial.STOPBITS_TWO
|
||||
self.dump_port_settings()
|
||||
elif c == '3': # 3 -> change to 1.5 stop bits
|
||||
self.serial.stopbits = serial.STOPBITS_ONE_POINT_FIVE
|
||||
self.dump_port_settings()
|
||||
elif c in 'xX': # X -> change software flow control
|
||||
self.serial.xonxoff = (c == 'X')
|
||||
self.dump_port_settings()
|
||||
elif c in 'rR': # R -> change hardware flow control
|
||||
self.serial.rtscts = (c == 'R')
|
||||
self.dump_port_settings()
|
||||
else:
|
||||
sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c)))
|
||||
|
||||
def upload_file(self):
|
||||
"""Ask user for filenname and send its contents"""
|
||||
sys.stderr.write('\n--- File to upload: ')
|
||||
sys.stderr.flush()
|
||||
with self.console:
|
||||
filename = sys.stdin.readline().rstrip('\r\n')
|
||||
if filename:
|
||||
try:
|
||||
with open(filename, 'rb') as f:
|
||||
sys.stderr.write('--- Sending file {} ---\n'.format(filename))
|
||||
while True:
|
||||
block = f.read(1024)
|
||||
if not block:
|
||||
break
|
||||
self.serial.write(block)
|
||||
# Wait for output buffer to drain.
|
||||
self.serial.flush()
|
||||
sys.stderr.write('.') # Progress indicator.
|
||||
sys.stderr.write('\n--- File {} sent ---\n'.format(filename))
|
||||
except IOError as e:
|
||||
sys.stderr.write('--- ERROR opening file {}: {} ---\n'.format(filename, e))
|
||||
|
||||
def change_filter(self):
|
||||
"""change the i/o transformations"""
|
||||
sys.stderr.write('\n--- Available Filters:\n')
|
||||
sys.stderr.write('\n'.join(
|
||||
'--- {:<10} = {.__doc__}'.format(k, v)
|
||||
for k, v in sorted(TRANSFORMATIONS.items())))
|
||||
sys.stderr.write('\n--- Enter new filter name(s) [{}]: '.format(' '.join(self.filters)))
|
||||
with self.console:
|
||||
new_filters = sys.stdin.readline().lower().split()
|
||||
if new_filters:
|
||||
for f in new_filters:
|
||||
if f not in TRANSFORMATIONS:
|
||||
sys.stderr.write('--- unknown filter: {}\n'.format(repr(f)))
|
||||
break
|
||||
else:
|
||||
self.filters = new_filters
|
||||
self.update_transformations()
|
||||
sys.stderr.write('--- filters: {}\n'.format(' '.join(self.filters)))
|
||||
|
||||
def change_encoding(self):
|
||||
"""change encoding on the serial port"""
|
||||
sys.stderr.write('\n--- Enter new encoding name [{}]: '.format(self.input_encoding))
|
||||
with self.console:
|
||||
new_encoding = sys.stdin.readline().strip()
|
||||
if new_encoding:
|
||||
try:
|
||||
codecs.lookup(new_encoding)
|
||||
except LookupError:
|
||||
sys.stderr.write('--- invalid encoding name: {}\n'.format(new_encoding))
|
||||
else:
|
||||
self.set_rx_encoding(new_encoding)
|
||||
self.set_tx_encoding(new_encoding)
|
||||
sys.stderr.write('--- serial input encoding: {}\n'.format(self.input_encoding))
|
||||
sys.stderr.write('--- serial output encoding: {}\n'.format(self.output_encoding))
|
||||
|
||||
def change_baudrate(self):
|
||||
"""change the baudrate"""
|
||||
sys.stderr.write('\n--- Baudrate: ')
|
||||
sys.stderr.flush()
|
||||
with self.console:
|
||||
backup = self.serial.baudrate
|
||||
try:
|
||||
self.serial.baudrate = int(sys.stdin.readline().strip())
|
||||
except ValueError as e:
|
||||
sys.stderr.write('--- ERROR setting baudrate: {} ---\n'.format(e))
|
||||
self.serial.baudrate = backup
|
||||
else:
|
||||
self.dump_port_settings()
|
||||
|
||||
def change_port(self):
|
||||
"""Have a conversation with the user to change the serial port"""
|
||||
with self.console:
|
||||
try:
|
||||
port = ask_for_port()
|
||||
except KeyboardInterrupt:
|
||||
port = None
|
||||
if port and port != self.serial.port:
|
||||
# reader thread needs to be shut down
|
||||
self._stop_reader()
|
||||
# save settings
|
||||
settings = self.serial.getSettingsDict()
|
||||
try:
|
||||
new_serial = serial.serial_for_url(port, do_not_open=True)
|
||||
# restore settings and open
|
||||
new_serial.applySettingsDict(settings)
|
||||
new_serial.rts = self.serial.rts
|
||||
new_serial.dtr = self.serial.dtr
|
||||
new_serial.open()
|
||||
new_serial.break_condition = self.serial.break_condition
|
||||
except Exception as e:
|
||||
sys.stderr.write('--- ERROR opening new port: {} ---\n'.format(e))
|
||||
new_serial.close()
|
||||
else:
|
||||
self.serial.close()
|
||||
self.serial = new_serial
|
||||
sys.stderr.write('--- Port changed to: {} ---\n'.format(self.serial.port))
|
||||
# and restart the reader thread
|
||||
self._start_reader()
|
||||
|
||||
def suspend_port(self):
|
||||
"""\
|
||||
open port temporarily, allow reconnect, exit and port change to get
|
||||
out of the loop
|
||||
"""
|
||||
# reader thread needs to be shut down
|
||||
self._stop_reader()
|
||||
self.serial.close()
|
||||
sys.stderr.write('\n--- Port closed: {} ---\n'.format(self.serial.port))
|
||||
do_change_port = False
|
||||
while not self.serial.is_open:
|
||||
sys.stderr.write('--- Quit: {exit} | p: port change | any other key to reconnect ---\n'.format(
|
||||
exit=key_description(self.exit_character)))
|
||||
k = self.console.getkey()
|
||||
if k == self.exit_character:
|
||||
self.stop() # exit app
|
||||
break
|
||||
elif k in 'pP':
|
||||
do_change_port = True
|
||||
break
|
||||
try:
|
||||
self.serial.open()
|
||||
except Exception as e:
|
||||
sys.stderr.write('--- ERROR opening port: {} ---\n'.format(e))
|
||||
if do_change_port:
|
||||
self.change_port()
|
||||
else:
|
||||
# and restart the reader thread
|
||||
self._start_reader()
|
||||
sys.stderr.write('--- Port opened: {} ---\n'.format(self.serial.port))
|
||||
|
||||
def get_help_text(self):
|
||||
"""return the help text"""
|
||||
# help text, starts with blank line!
|
||||
return """
|
||||
--- pySerial ({version}) - miniterm - help
|
||||
---
|
||||
--- {exit:8} Exit program
|
||||
--- {menu:8} Menu escape key, followed by:
|
||||
--- Menu keys:
|
||||
--- {menu:7} Send the menu character itself to remote
|
||||
--- {exit:7} Send the exit character itself to remote
|
||||
--- {info:7} Show info
|
||||
--- {upload:7} Upload file (prompt will be shown)
|
||||
--- {repr:7} encoding
|
||||
--- {filter:7} edit filters
|
||||
--- Toggles:
|
||||
--- {rts:7} RTS {dtr:7} DTR {brk:7} BREAK
|
||||
--- {echo:7} echo {eol:7} EOL
|
||||
---
|
||||
--- Port settings ({menu} followed by the following):
|
||||
--- p change port
|
||||
--- 7 8 set data bits
|
||||
--- N E O S M change parity (None, Even, Odd, Space, Mark)
|
||||
--- 1 2 3 set stop bits (1, 2, 1.5)
|
||||
--- b change baud rate
|
||||
--- x X disable/enable software flow control
|
||||
--- r R disable/enable hardware flow control
|
||||
""".format(version=getattr(serial, 'VERSION', 'unknown version'),
|
||||
exit=key_description(self.exit_character),
|
||||
menu=key_description(self.menu_character),
|
||||
rts=key_description('\x12'),
|
||||
dtr=key_description('\x04'),
|
||||
brk=key_description('\x02'),
|
||||
echo=key_description('\x05'),
|
||||
info=key_description('\x09'),
|
||||
upload=key_description('\x15'),
|
||||
repr=key_description('\x01'),
|
||||
filter=key_description('\x06'),
|
||||
eol=key_description('\x0c'))
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# default args can be used to override when calling main() from an other script
|
||||
# e.g to create a miniterm-my-device.py
|
||||
def main(default_port=None, default_baudrate=9600, default_rts=None, default_dtr=None):
|
||||
"""Command line tool, entry point"""
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Miniterm - A simple terminal program for the serial port.")
|
||||
|
||||
parser.add_argument(
|
||||
"port",
|
||||
nargs='?',
|
||||
help="serial port name ('-' to show port list)",
|
||||
default=default_port)
|
||||
|
||||
parser.add_argument(
|
||||
"baudrate",
|
||||
nargs='?',
|
||||
type=int,
|
||||
help="set baud rate, default: %(default)s",
|
||||
default=default_baudrate)
|
||||
|
||||
group = parser.add_argument_group("port settings")
|
||||
|
||||
group.add_argument(
|
||||
"--parity",
|
||||
choices=['N', 'E', 'O', 'S', 'M'],
|
||||
type=lambda c: c.upper(),
|
||||
help="set parity, one of {N E O S M}, default: N",
|
||||
default='N')
|
||||
|
||||
group.add_argument(
|
||||
"--rtscts",
|
||||
action="store_true",
|
||||
help="enable RTS/CTS flow control (default off)",
|
||||
default=False)
|
||||
|
||||
group.add_argument(
|
||||
"--xonxoff",
|
||||
action="store_true",
|
||||
help="enable software flow control (default off)",
|
||||
default=False)
|
||||
|
||||
group.add_argument(
|
||||
"--rts",
|
||||
type=int,
|
||||
help="set initial RTS line state (possible values: 0, 1)",
|
||||
default=default_rts)
|
||||
|
||||
group.add_argument(
|
||||
"--dtr",
|
||||
type=int,
|
||||
help="set initial DTR line state (possible values: 0, 1)",
|
||||
default=default_dtr)
|
||||
|
||||
group.add_argument(
|
||||
"--ask",
|
||||
action="store_true",
|
||||
help="ask again for port when open fails",
|
||||
default=False)
|
||||
|
||||
group = parser.add_argument_group("data handling")
|
||||
|
||||
group.add_argument(
|
||||
"-e", "--echo",
|
||||
action="store_true",
|
||||
help="enable local echo (default off)",
|
||||
default=False)
|
||||
|
||||
group.add_argument(
|
||||
"--encoding",
|
||||
dest="serial_port_encoding",
|
||||
metavar="CODEC",
|
||||
help="set the encoding for the serial port (e.g. hexlify, Latin1, UTF-8), default: %(default)s",
|
||||
default='UTF-8')
|
||||
|
||||
group.add_argument(
|
||||
"-f", "--filter",
|
||||
action="append",
|
||||
metavar="NAME",
|
||||
help="add text transformation",
|
||||
default=[])
|
||||
|
||||
group.add_argument(
|
||||
"--eol",
|
||||
choices=['CR', 'LF', 'CRLF'],
|
||||
type=lambda c: c.upper(),
|
||||
help="end of line mode",
|
||||
default='CRLF')
|
||||
|
||||
group.add_argument(
|
||||
"--raw",
|
||||
action="store_true",
|
||||
help="Do no apply any encodings/transformations",
|
||||
default=False)
|
||||
|
||||
group = parser.add_argument_group("hotkeys")
|
||||
|
||||
group.add_argument(
|
||||
"--exit-char",
|
||||
type=int,
|
||||
metavar='NUM',
|
||||
help="Unicode of special character that is used to exit the application, default: %(default)s",
|
||||
default=0x1d) # GS/CTRL+]
|
||||
|
||||
group.add_argument(
|
||||
"--menu-char",
|
||||
type=int,
|
||||
metavar='NUM',
|
||||
help="Unicode code of special character that is used to control miniterm (menu), default: %(default)s",
|
||||
default=0x14) # Menu: CTRL+T
|
||||
|
||||
group = parser.add_argument_group("diagnostics")
|
||||
|
||||
group.add_argument(
|
||||
"-q", "--quiet",
|
||||
action="store_true",
|
||||
help="suppress non-error messages",
|
||||
default=False)
|
||||
|
||||
group.add_argument(
|
||||
"--develop",
|
||||
action="store_true",
|
||||
help="show Python traceback on error",
|
||||
default=False)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.menu_char == args.exit_char:
|
||||
parser.error('--exit-char can not be the same as --menu-char')
|
||||
|
||||
if args.filter:
|
||||
if 'help' in args.filter:
|
||||
sys.stderr.write('Available filters:\n')
|
||||
sys.stderr.write('\n'.join(
|
||||
'{:<10} = {.__doc__}'.format(k, v)
|
||||
for k, v in sorted(TRANSFORMATIONS.items())))
|
||||
sys.stderr.write('\n')
|
||||
sys.exit(1)
|
||||
filters = args.filter
|
||||
else:
|
||||
filters = ['default']
|
||||
|
||||
while True:
|
||||
# no port given on command line -> ask user now
|
||||
if args.port is None or args.port == '-':
|
||||
try:
|
||||
args.port = ask_for_port()
|
||||
except KeyboardInterrupt:
|
||||
sys.stderr.write('\n')
|
||||
parser.error('user aborted and port is not given')
|
||||
else:
|
||||
if not args.port:
|
||||
parser.error('port is not given')
|
||||
try:
|
||||
serial_instance = serial.serial_for_url(
|
||||
args.port,
|
||||
args.baudrate,
|
||||
parity=args.parity,
|
||||
rtscts=args.rtscts,
|
||||
xonxoff=args.xonxoff,
|
||||
do_not_open=True)
|
||||
|
||||
if not hasattr(serial_instance, 'cancel_read'):
|
||||
# enable timeout for alive flag polling if cancel_read is not available
|
||||
serial_instance.timeout = 1
|
||||
|
||||
if args.dtr is not None:
|
||||
if not args.quiet:
|
||||
sys.stderr.write('--- forcing DTR {}\n'.format('active' if args.dtr else 'inactive'))
|
||||
serial_instance.dtr = args.dtr
|
||||
if args.rts is not None:
|
||||
if not args.quiet:
|
||||
sys.stderr.write('--- forcing RTS {}\n'.format('active' if args.rts else 'inactive'))
|
||||
serial_instance.rts = args.rts
|
||||
|
||||
serial_instance.open()
|
||||
except serial.SerialException as e:
|
||||
sys.stderr.write('could not open port {}: {}\n'.format(repr(args.port), e))
|
||||
if args.develop:
|
||||
raise
|
||||
if not args.ask:
|
||||
sys.exit(1)
|
||||
else:
|
||||
args.port = '-'
|
||||
else:
|
||||
break
|
||||
|
||||
miniterm = Miniterm(
|
||||
serial_instance,
|
||||
echo=args.echo,
|
||||
eol=args.eol.lower(),
|
||||
filters=filters)
|
||||
miniterm.exit_character = unichr(args.exit_char)
|
||||
miniterm.menu_character = unichr(args.menu_char)
|
||||
miniterm.raw = args.raw
|
||||
miniterm.set_rx_encoding(args.serial_port_encoding)
|
||||
miniterm.set_tx_encoding(args.serial_port_encoding)
|
||||
|
||||
if not args.quiet:
|
||||
sys.stderr.write('--- Miniterm on {p.name} {p.baudrate},{p.bytesize},{p.parity},{p.stopbits} ---\n'.format(
|
||||
p=miniterm.serial))
|
||||
sys.stderr.write('--- Quit: {} | Menu: {} | Help: {} followed by {} ---\n'.format(
|
||||
key_description(miniterm.exit_character),
|
||||
key_description(miniterm.menu_character),
|
||||
key_description(miniterm.menu_character),
|
||||
key_description('\x08')))
|
||||
|
||||
miniterm.start()
|
||||
try:
|
||||
miniterm.join(True)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
if not args.quiet:
|
||||
sys.stderr.write("\n--- exit ---\n")
|
||||
miniterm.join()
|
||||
miniterm.close()
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Binary file not shown.
@@ -1,12 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'future==0.17.1','console_scripts','pasteurize'
|
||||
__requires__ = 'future==0.17.1'
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point('future==0.17.1', 'console_scripts', 'pasteurize')()
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip._internal import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip._internal import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/root/projekti/TeraHz/backend/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pip._internal import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@@ -1 +0,0 @@
|
||||
python3
|
||||
@@ -1 +0,0 @@
|
||||
/usr/bin/python3
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,39 +0,0 @@
|
||||
Copyright © 2014 by the Pallets team.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms of the software as
|
||||
well as documentation, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the copyright 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 AND DOCUMENTATION 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
----
|
||||
|
||||
Click uses parts of optparse written by Gregory P. Ward and maintained
|
||||
by the Python Software Foundation. This is limited to code in parser.py.
|
||||
|
||||
Copyright © 2001-2006 Gregory P. Ward. All rights reserved.
|
||||
Copyright © 2002-2006 Python Software Foundation. All rights reserved.
|
||||
@@ -1,121 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: Click
|
||||
Version: 7.0
|
||||
Summary: Composable command line interface toolkit
|
||||
Home-page: https://palletsprojects.com/p/click/
|
||||
Author: Armin Ronacher
|
||||
Author-email: armin.ronacher@active-4.com
|
||||
Maintainer: Pallets Team
|
||||
Maintainer-email: contact@palletsprojects.com
|
||||
License: BSD
|
||||
Project-URL: Documentation, https://click.palletsprojects.com/
|
||||
Project-URL: Code, https://github.com/pallets/click
|
||||
Project-URL: Issue tracker, https://github.com/pallets/click/issues
|
||||
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
|
||||
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
||||
|
||||
\$ click\_
|
||||
==========
|
||||
|
||||
Click is a Python package for creating beautiful command line interfaces
|
||||
in a composable way with as little code as necessary. It's the "Command
|
||||
Line Interface Creation Kit". It's highly configurable but comes with
|
||||
sensible defaults out of the box.
|
||||
|
||||
It aims to make the process of writing command line tools quick and fun
|
||||
while also preventing any frustration caused by the inability to
|
||||
implement an intended CLI API.
|
||||
|
||||
Click in three points:
|
||||
|
||||
- Arbitrary nesting of commands
|
||||
- Automatic help page generation
|
||||
- Supports lazy loading of subcommands at runtime
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Install and update using `pip`_:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pip install click
|
||||
|
||||
Click supports Python 3.4 and newer, Python 2.7, and PyPy.
|
||||
|
||||
.. _pip: https://pip.pypa.io/en/stable/quickstart/
|
||||
|
||||
|
||||
A Simple Example
|
||||
----------------
|
||||
|
||||
What does it look like? Here is an example of a simple Click program:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import click
|
||||
|
||||
@click.command()
|
||||
@click.option("--count", default=1, help="Number of greetings.")
|
||||
@click.option("--name", prompt="Your name",
|
||||
help="The person to greet.")
|
||||
def hello(count, name):
|
||||
"""Simple program that greets NAME for a total of COUNT times."""
|
||||
for _ in range(count):
|
||||
click.echo("Hello, %s!" % name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
hello()
|
||||
|
||||
And what it looks like when run:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python hello.py --count=3
|
||||
Your name: Click
|
||||
Hello, Click!
|
||||
Hello, Click!
|
||||
Hello, Click!
|
||||
|
||||
|
||||
Donate
|
||||
------
|
||||
|
||||
The Pallets organization develops and supports Click and other popular
|
||||
packages. In order to grow the community of contributors and users, and
|
||||
allow the maintainers to devote more time to the projects, `please
|
||||
donate today`_.
|
||||
|
||||
.. _please donate today: https://palletsprojects.com/donate
|
||||
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
* Website: https://palletsprojects.com/p/click/
|
||||
* Documentation: https://click.palletsprojects.com/
|
||||
* License: `BSD <https://github.com/pallets/click/blob/master/LICENSE.rst>`_
|
||||
* Releases: https://pypi.org/project/click/
|
||||
* Code: https://github.com/pallets/click
|
||||
* Issue tracker: https://github.com/pallets/click/issues
|
||||
* Test status:
|
||||
|
||||
* Linux, Mac: https://travis-ci.org/pallets/click
|
||||
* Windows: https://ci.appveyor.com/project/pallets/click
|
||||
|
||||
* Test coverage: https://codecov.io/gh/pallets/click
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
Click-7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
Click-7.0.dist-info/LICENSE.txt,sha256=4hIxn676T0Wcisk3_chVcECjyrivKTZsoqSNI5AlIlw,1876
|
||||
Click-7.0.dist-info/METADATA,sha256=-r8jeke3Zer4diRvT1MjFZuiJ6yTT_qFP39svLqdaLI,3516
|
||||
Click-7.0.dist-info/RECORD,,
|
||||
Click-7.0.dist-info/WHEEL,sha256=gduuPyBvFJQSQ0zdyxF7k0zynDXbIbvg5ZBHoXum5uk,110
|
||||
Click-7.0.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6
|
||||
click/__init__.py,sha256=HjGThQ7tef9kkwCV371TBnrf0SAi6fKfU_jtEnbYTvQ,2789
|
||||
click/__pycache__/__init__.cpython-36.pyc,,
|
||||
click/__pycache__/_bashcomplete.cpython-36.pyc,,
|
||||
click/__pycache__/_compat.cpython-36.pyc,,
|
||||
click/__pycache__/_termui_impl.cpython-36.pyc,,
|
||||
click/__pycache__/_textwrap.cpython-36.pyc,,
|
||||
click/__pycache__/_unicodefun.cpython-36.pyc,,
|
||||
click/__pycache__/_winconsole.cpython-36.pyc,,
|
||||
click/__pycache__/core.cpython-36.pyc,,
|
||||
click/__pycache__/decorators.cpython-36.pyc,,
|
||||
click/__pycache__/exceptions.cpython-36.pyc,,
|
||||
click/__pycache__/formatting.cpython-36.pyc,,
|
||||
click/__pycache__/globals.cpython-36.pyc,,
|
||||
click/__pycache__/parser.cpython-36.pyc,,
|
||||
click/__pycache__/termui.cpython-36.pyc,,
|
||||
click/__pycache__/testing.cpython-36.pyc,,
|
||||
click/__pycache__/types.cpython-36.pyc,,
|
||||
click/__pycache__/utils.cpython-36.pyc,,
|
||||
click/_bashcomplete.py,sha256=iaNUmtxag0YPfxba3TDYCNietiTMQIrvhRLj-H8okFU,11014
|
||||
click/_compat.py,sha256=vYmvoj4opPxo-c-2GMQQjYT_r_QkOKybkfGoeVrt0dA,23399
|
||||
click/_termui_impl.py,sha256=xHmLtOJhKUCVD6168yucJ9fknUJPAMs0eUTPgVUO-GQ,19611
|
||||
click/_textwrap.py,sha256=gwS4m7bdQiJnzaDG8osFcRb-5vn4t4l2qSCy-5csCEc,1198
|
||||
click/_unicodefun.py,sha256=QHy2_5jYlX-36O-JVrTHNnHOqg8tquUR0HmQFev7Ics,4364
|
||||
click/_winconsole.py,sha256=PPWVak8Iikm_gAPsxMrzwsVFCvHgaW3jPaDWZ1JBl3U,8965
|
||||
click/core.py,sha256=q8FLcDZsagBGSRe5Y9Hi_FGvAeZvusNfoO5EkhkSQ8Y,75305
|
||||
click/decorators.py,sha256=idKt6duLUUfAFftrHoREi8MJSd39XW36pUVHthdglwk,11226
|
||||
click/exceptions.py,sha256=CNpAjBAE7qjaV4WChxQeak95e5yUOau8AsvT-8m6wss,7663
|
||||
click/formatting.py,sha256=eh-cypTUAhpI3HD-K4ZpR3vCiURIO62xXvKkR3tNUTM,8889
|
||||
click/globals.py,sha256=oQkou3ZQ5DgrbVM6BwIBirwiqozbjfirzsLGAlLRRdg,1514
|
||||
click/parser.py,sha256=m-nGZz4VwprM42_qtFlWFGo7yRJQxkBlRcZodoH593Y,15510
|
||||
click/termui.py,sha256=o_ZXB2jyvL2Rce7P_bFGq452iyBq9ykJyRApIPMCZO0,23207
|
||||
click/testing.py,sha256=aYGqY_iWLu2p4k7lkuJ6t3fqpf6aPGqTsyLzNY_ngKg,13062
|
||||
click/types.py,sha256=2Q929p-aBP_ZYuMFJqJR-Ipucofv3fmDc5JzBDPmzJU,23287
|
||||
click/utils.py,sha256=6-D0WkAxvv9FkgHXSHwDIv0l9Gdx9Mm6Z5vuKNLIfZI,15763
|
||||
@@ -1,6 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.31.1)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
click
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,31 +0,0 @@
|
||||
Copyright © 2010 by the Pallets team.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms of the software as
|
||||
well as documentation, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright 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 AND DOCUMENTATION 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
@@ -1,130 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: Flask
|
||||
Version: 1.0.2
|
||||
Summary: A simple framework for building complex web applications.
|
||||
Home-page: https://www.palletsprojects.com/p/flask/
|
||||
Author: Armin Ronacher
|
||||
Author-email: armin.ronacher@active-4.com
|
||||
Maintainer: Pallets team
|
||||
Maintainer-email: contact@palletsprojects.com
|
||||
License: BSD
|
||||
Project-URL: Documentation, http://flask.pocoo.org/docs/
|
||||
Project-URL: Code, https://github.com/pallets/flask
|
||||
Project-URL: Issue tracker, https://github.com/pallets/flask/issues
|
||||
Platform: any
|
||||
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: 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: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
||||
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Provides-Extra: dev
|
||||
Provides-Extra: docs
|
||||
Provides-Extra: dotenv
|
||||
Requires-Dist: Werkzeug (>=0.14)
|
||||
Requires-Dist: Jinja2 (>=2.10)
|
||||
Requires-Dist: itsdangerous (>=0.24)
|
||||
Requires-Dist: click (>=5.1)
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: pytest (>=3); extra == 'dev'
|
||||
Requires-Dist: coverage; extra == 'dev'
|
||||
Requires-Dist: tox; extra == 'dev'
|
||||
Requires-Dist: sphinx; extra == 'dev'
|
||||
Requires-Dist: pallets-sphinx-themes; extra == 'dev'
|
||||
Requires-Dist: sphinxcontrib-log-cabinet; extra == 'dev'
|
||||
Provides-Extra: docs
|
||||
Requires-Dist: sphinx; extra == 'docs'
|
||||
Requires-Dist: pallets-sphinx-themes; extra == 'docs'
|
||||
Requires-Dist: sphinxcontrib-log-cabinet; extra == 'docs'
|
||||
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.
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Install and update using `pip`_:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
pip install -U Flask
|
||||
|
||||
|
||||
A Simple Example
|
||||
----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def hello():
|
||||
return 'Hello, World!'
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ FLASK_APP=hello.py flask run
|
||||
* Serving Flask app "hello"
|
||||
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
|
||||
|
||||
|
||||
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://psfmember.org/civicrm/contribute/transact?reset=1&id=20
|
||||
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
* Website: https://www.palletsprojects.com/p/flask/
|
||||
* Documentation: http://flask.pocoo.org/docs/
|
||||
* License: `BSD <https://github.com/pallets/flask/blob/master/LICENSE>`_
|
||||
* Releases: https://pypi.org/project/Flask/
|
||||
* Code: https://github.com/pallets/flask
|
||||
* Issue tracker: https://github.com/pallets/flask/issues
|
||||
* Test status:
|
||||
|
||||
* Linux, Mac: https://travis-ci.org/pallets/flask
|
||||
* Windows: https://ci.appveyor.com/project/pallets/flask
|
||||
|
||||
* Test coverage: https://codecov.io/gh/pallets/flask
|
||||
|
||||
.. _WSGI: https://wsgi.readthedocs.io
|
||||
.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/
|
||||
.. _Jinja: https://www.palletsprojects.com/p/jinja/
|
||||
.. _pip: https://pip.pypa.io/en/stable/quickstart/
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
../../../bin/flask,sha256=ja9nrYfRFZV2nf3KLUUe1glXY9Jpqr193oPl5IT_Igw,241
|
||||
Flask-1.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
Flask-1.0.2.dist-info/LICENSE.txt,sha256=ziEXA3AIuaiUn1qe4cd1XxCESWTYrk4TjN7Qb06J3l8,1575
|
||||
Flask-1.0.2.dist-info/METADATA,sha256=iA5tiNWzTtgCVe80aTZGNWsckj853fJyfvHs9U-WZRk,4182
|
||||
Flask-1.0.2.dist-info/RECORD,,
|
||||
Flask-1.0.2.dist-info/WHEEL,sha256=J3CsTk7Mf2JNUyhImI-mjX-fmI4oDjyiXgWT4qgZiCE,110
|
||||
Flask-1.0.2.dist-info/entry_points.txt,sha256=gBLA1aKg0OYR8AhbAfg8lnburHtKcgJLDU52BBctN0k,42
|
||||
Flask-1.0.2.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6
|
||||
flask/__init__.py,sha256=qq8lK6QQbxJALf1igz7qsvUwOTAoKvFGfdLm7jPNsso,1673
|
||||
flask/__main__.py,sha256=pgIXrHhxM5MAMvgzAqWpw_t6AXZ1zG38us4JRgJKtxk,291
|
||||
flask/__pycache__/__init__.cpython-36.pyc,,
|
||||
flask/__pycache__/__main__.cpython-36.pyc,,
|
||||
flask/__pycache__/_compat.cpython-36.pyc,,
|
||||
flask/__pycache__/app.cpython-36.pyc,,
|
||||
flask/__pycache__/blueprints.cpython-36.pyc,,
|
||||
flask/__pycache__/cli.cpython-36.pyc,,
|
||||
flask/__pycache__/config.cpython-36.pyc,,
|
||||
flask/__pycache__/ctx.cpython-36.pyc,,
|
||||
flask/__pycache__/debughelpers.cpython-36.pyc,,
|
||||
flask/__pycache__/globals.cpython-36.pyc,,
|
||||
flask/__pycache__/helpers.cpython-36.pyc,,
|
||||
flask/__pycache__/logging.cpython-36.pyc,,
|
||||
flask/__pycache__/sessions.cpython-36.pyc,,
|
||||
flask/__pycache__/signals.cpython-36.pyc,,
|
||||
flask/__pycache__/templating.cpython-36.pyc,,
|
||||
flask/__pycache__/testing.cpython-36.pyc,,
|
||||
flask/__pycache__/views.cpython-36.pyc,,
|
||||
flask/__pycache__/wrappers.cpython-36.pyc,,
|
||||
flask/_compat.py,sha256=UDFGhosh6mOdNB-4evKPuneHum1OpcAlwTNJCRm0irQ,2892
|
||||
flask/app.py,sha256=ahpe3T8w98rQd_Er5d7uDxK57S1nnqGQx3V3hirBovU,94147
|
||||
flask/blueprints.py,sha256=Cyhl_x99tgwqEZPtNDJUFneAfVJxWfEU4bQA7zWS6VU,18331
|
||||
flask/cli.py,sha256=30QYAO10Do9LbZYCLgfI_xhKjASdLopL8wKKVUGS2oA,29442
|
||||
flask/config.py,sha256=kznUhj4DLYxsTF_4kfDG8GEHto1oZG_kqblyrLFtpqQ,9951
|
||||
flask/ctx.py,sha256=leFzS9fzmo0uaLCdxpHc5_iiJZ1H0X_Ig4yPCOvT--g,16224
|
||||
flask/debughelpers.py,sha256=1ceC-UyqZTd4KsJkf0OObHPsVt5R3T6vnmYhiWBjV-w,6479
|
||||
flask/globals.py,sha256=pGg72QW_-4xUfsI33I5L_y76c21AeqfSqXDcbd8wvXU,1649
|
||||
flask/helpers.py,sha256=YCl8D1plTO1evEYP4KIgaY3H8Izww5j4EdgRJ89oHTw,40106
|
||||
flask/json/__init__.py,sha256=Ns1Hj805XIxuBMh2z0dYnMVfb_KUgLzDmP3WoUYaPhw,10729
|
||||
flask/json/__pycache__/__init__.cpython-36.pyc,,
|
||||
flask/json/__pycache__/tag.cpython-36.pyc,,
|
||||
flask/json/tag.py,sha256=9ehzrmt5k7hxf7ZEK0NOs3swvQyU9fWNe-pnYe69N60,8223
|
||||
flask/logging.py,sha256=qV9h0vt7NIRkKM9OHDWndzO61E5CeBMlqPJyTt-W2Wc,2231
|
||||
flask/sessions.py,sha256=2XHV4ASREhSEZ8bsPQW6pNVNuFtbR-04BzfKg0AfvHo,14452
|
||||
flask/signals.py,sha256=BGQbVyCYXnzKK2DVCzppKFyWN1qmrtW1QMAYUs-1Nr8,2211
|
||||
flask/templating.py,sha256=FDfWMbpgpC3qObW8GGXRAVrkHFF8K4CHOJymB1wvULI,4914
|
||||
flask/testing.py,sha256=XD3gWNvLUV8dqVHwKd9tZzsj81fSHtjOphQ1wTNtlMs,9379
|
||||
flask/views.py,sha256=Wy-_WkUVtCfE2zCXYeJehNgHuEtviE4v3HYfJ--MpbY,5733
|
||||
flask/wrappers.py,sha256=1Z9hF5-hXQajn_58XITQFRY8efv3Vy3uZ0avBfZu6XI,7511
|
||||
@@ -1,6 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.31.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[console_scripts]
|
||||
flask = flask.cli:main
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
flask
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
Jinja2
|
||||
~~~~~~
|
||||
|
||||
Jinja2 is a template engine written in pure Python. It provides a
|
||||
`Django`_ inspired non-XML syntax but supports inline expressions and
|
||||
an optional `sandboxed`_ environment.
|
||||
|
||||
Nutshell
|
||||
--------
|
||||
|
||||
Here a small example of a Jinja template::
|
||||
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Memberlist{% endblock %}
|
||||
{% block content %}
|
||||
<ul>
|
||||
{% for user in users %}
|
||||
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
Philosophy
|
||||
----------
|
||||
|
||||
Application logic is for the controller but don't try to make the life
|
||||
for the template designer too hard by giving him too few functionality.
|
||||
|
||||
For more informations visit the new `Jinja2 webpage`_ and `documentation`_.
|
||||
|
||||
.. _sandboxed: https://en.wikipedia.org/wiki/Sandbox_(computer_security)
|
||||
.. _Django: https://www.djangoproject.com/
|
||||
.. _Jinja2 webpage: http://jinja.pocoo.org/
|
||||
.. _documentation: http://jinja.pocoo.org/2/documentation/
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,31 +0,0 @@
|
||||
Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The names of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER 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.
|
||||
@@ -1,68 +0,0 @@
|
||||
Metadata-Version: 2.0
|
||||
Name: Jinja2
|
||||
Version: 2.10
|
||||
Summary: A small but fast and easy to use stand-alone template engine written in pure python.
|
||||
Home-page: http://jinja.pocoo.org/
|
||||
Author: Armin Ronacher
|
||||
Author-email: armin.ronacher@active-4.com
|
||||
License: BSD
|
||||
Description-Content-Type: UNKNOWN
|
||||
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.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Text Processing :: Markup :: HTML
|
||||
Requires-Dist: MarkupSafe (>=0.23)
|
||||
Provides-Extra: i18n
|
||||
Requires-Dist: Babel (>=0.8); extra == 'i18n'
|
||||
|
||||
|
||||
Jinja2
|
||||
~~~~~~
|
||||
|
||||
Jinja2 is a template engine written in pure Python. It provides a
|
||||
`Django`_ inspired non-XML syntax but supports inline expressions and
|
||||
an optional `sandboxed`_ environment.
|
||||
|
||||
Nutshell
|
||||
--------
|
||||
|
||||
Here a small example of a Jinja template::
|
||||
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Memberlist{% endblock %}
|
||||
{% block content %}
|
||||
<ul>
|
||||
{% for user in users %}
|
||||
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
Philosophy
|
||||
----------
|
||||
|
||||
Application logic is for the controller but don't try to make the life
|
||||
for the template designer too hard by giving him too few functionality.
|
||||
|
||||
For more informations visit the new `Jinja2 webpage`_ and `documentation`_.
|
||||
|
||||
.. _sandboxed: https://en.wikipedia.org/wiki/Sandbox_(computer_security)
|
||||
.. _Django: https://www.djangoproject.com/
|
||||
.. _Jinja2 webpage: http://jinja.pocoo.org/
|
||||
.. _documentation: http://jinja.pocoo.org/2/documentation/
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
Jinja2-2.10.dist-info/DESCRIPTION.rst,sha256=b5ckFDoM7vVtz_mAsJD4OPteFKCqE7beu353g4COoYI,978
|
||||
Jinja2-2.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
Jinja2-2.10.dist-info/LICENSE.txt,sha256=JvzUNv3Io51EiWrAPm8d_SXjhJnEjyDYvB3Tvwqqils,1554
|
||||
Jinja2-2.10.dist-info/METADATA,sha256=18EgU8zR6-av-0-5y_gXebzK4GnBB_76lALUsl-6QHM,2258
|
||||
Jinja2-2.10.dist-info/RECORD,,
|
||||
Jinja2-2.10.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110
|
||||
Jinja2-2.10.dist-info/entry_points.txt,sha256=NdzVcOrqyNyKDxD09aERj__3bFx2paZhizFDsKmVhiA,72
|
||||
Jinja2-2.10.dist-info/metadata.json,sha256=NPUJ9TMBxVQAv_kTJzvU8HwmP-4XZvbK9mz6_4YUVl4,1473
|
||||
Jinja2-2.10.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7
|
||||
jinja2/__init__.py,sha256=xJHjaMoy51_KXn1wf0cysH6tUUifUxZCwSOfcJGEYZw,2614
|
||||
jinja2/__pycache__/__init__.cpython-36.pyc,,
|
||||
jinja2/__pycache__/_compat.cpython-36.pyc,,
|
||||
jinja2/__pycache__/_identifier.cpython-36.pyc,,
|
||||
jinja2/__pycache__/asyncfilters.cpython-36.pyc,,
|
||||
jinja2/__pycache__/asyncsupport.cpython-36.pyc,,
|
||||
jinja2/__pycache__/bccache.cpython-36.pyc,,
|
||||
jinja2/__pycache__/compiler.cpython-36.pyc,,
|
||||
jinja2/__pycache__/constants.cpython-36.pyc,,
|
||||
jinja2/__pycache__/debug.cpython-36.pyc,,
|
||||
jinja2/__pycache__/defaults.cpython-36.pyc,,
|
||||
jinja2/__pycache__/environment.cpython-36.pyc,,
|
||||
jinja2/__pycache__/exceptions.cpython-36.pyc,,
|
||||
jinja2/__pycache__/ext.cpython-36.pyc,,
|
||||
jinja2/__pycache__/filters.cpython-36.pyc,,
|
||||
jinja2/__pycache__/idtracking.cpython-36.pyc,,
|
||||
jinja2/__pycache__/lexer.cpython-36.pyc,,
|
||||
jinja2/__pycache__/loaders.cpython-36.pyc,,
|
||||
jinja2/__pycache__/meta.cpython-36.pyc,,
|
||||
jinja2/__pycache__/nativetypes.cpython-36.pyc,,
|
||||
jinja2/__pycache__/nodes.cpython-36.pyc,,
|
||||
jinja2/__pycache__/optimizer.cpython-36.pyc,,
|
||||
jinja2/__pycache__/parser.cpython-36.pyc,,
|
||||
jinja2/__pycache__/runtime.cpython-36.pyc,,
|
||||
jinja2/__pycache__/sandbox.cpython-36.pyc,,
|
||||
jinja2/__pycache__/tests.cpython-36.pyc,,
|
||||
jinja2/__pycache__/utils.cpython-36.pyc,,
|
||||
jinja2/__pycache__/visitor.cpython-36.pyc,,
|
||||
jinja2/_compat.py,sha256=xP60CE5Qr8FTYcDE1f54tbZLKGvMwYml4-8T7Q4KG9k,2596
|
||||
jinja2/_identifier.py,sha256=W1QBSY-iJsyt6oR_nKSuNNCzV95vLIOYgUNPUI1d5gU,1726
|
||||
jinja2/asyncfilters.py,sha256=cTDPvrS8Hp_IkwsZ1m9af_lr5nHysw7uTa5gV0NmZVE,4144
|
||||
jinja2/asyncsupport.py,sha256=UErQ3YlTLaSjFb94P4MVn08-aVD9jJxty2JVfMRb-1M,7878
|
||||
jinja2/bccache.py,sha256=nQldx0ZRYANMyfvOihRoYFKSlUdd5vJkS7BjxNwlOZM,12794
|
||||
jinja2/compiler.py,sha256=BqC5U6JxObSRhblyT_a6Tp5GtEU5z3US1a4jLQaxxgo,65386
|
||||
jinja2/constants.py,sha256=uwwV8ZUhHhacAuz5PTwckfsbqBaqM7aKfyJL7kGX5YQ,1626
|
||||
jinja2/debug.py,sha256=WTVeUFGUa4v6ReCsYv-iVPa3pkNB75OinJt3PfxNdXs,12045
|
||||
jinja2/defaults.py,sha256=Em-95hmsJxIenDCZFB1YSvf9CNhe9rBmytN3yUrBcWA,1400
|
||||
jinja2/environment.py,sha256=VnkAkqw8JbjZct4tAyHlpBrka2vqB-Z58RAP-32P1ZY,50849
|
||||
jinja2/exceptions.py,sha256=_Rj-NVi98Q6AiEjYQOsP8dEIdu5AlmRHzcSNOPdWix4,4428
|
||||
jinja2/ext.py,sha256=atMQydEC86tN1zUsdQiHw5L5cF62nDbqGue25Yiu3N4,24500
|
||||
jinja2/filters.py,sha256=yOAJk0MsH-_gEC0i0U6NweVQhbtYaC-uE8xswHFLF4w,36528
|
||||
jinja2/idtracking.py,sha256=2GbDSzIvGArEBGLkovLkqEfmYxmWsEf8c3QZwM4uNsw,9197
|
||||
jinja2/lexer.py,sha256=ySEPoXd1g7wRjsuw23uimS6nkGN5aqrYwcOKxCaVMBQ,28559
|
||||
jinja2/loaders.py,sha256=xiTuURKAEObyym0nU8PCIXu_Qp8fn0AJ5oIADUUm-5Q,17382
|
||||
jinja2/meta.py,sha256=fmKHxkmZYAOm9QyWWy8EMd6eefAIh234rkBMW2X4ZR8,4340
|
||||
jinja2/nativetypes.py,sha256=_sJhS8f-8Q0QMIC0dm1YEdLyxEyoO-kch8qOL5xUDfE,7308
|
||||
jinja2/nodes.py,sha256=L10L_nQDfubLhO3XjpF9qz46FSh2clL-3e49ogVlMmA,30853
|
||||
jinja2/optimizer.py,sha256=MsdlFACJ0FRdPtjmCAdt7JQ9SGrXFaDNUaslsWQaG3M,1722
|
||||
jinja2/parser.py,sha256=lPzTEbcpTRBLw8ii6OYyExHeAhaZLMA05Hpv4ll3ULk,35875
|
||||
jinja2/runtime.py,sha256=DHdD38Pq8gj7uWQC5usJyWFoNWL317A9AvXOW_CLB34,27755
|
||||
jinja2/sandbox.py,sha256=TVyZHlNqqTzsv9fv2NvJNmSdWRHTguhyMHdxjWms32U,16708
|
||||
jinja2/tests.py,sha256=iJQLwbapZr-EKquTG_fVOVdwHUUKf3SX9eNkjQDF8oU,4237
|
||||
jinja2/utils.py,sha256=q24VupGZotQ-uOyrJxCaXtDWhZC1RgsQG7kcdmjck2Q,20629
|
||||
jinja2/visitor.py,sha256=JD1H1cANA29JcntFfN5fPyqQxB4bI4wC00BzZa-XHks,3316
|
||||
@@ -1,6 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.30.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
[babel.extractors]
|
||||
jinja2 = jinja2.ext:babel_extract[i18n]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://jinja.pocoo.org/"}}, "python.exports": {"babel.extractors": {"jinja2": "jinja2.ext:babel_extract [i18n]"}}}, "extras": ["i18n"], "generator": "bdist_wheel (0.30.0)", "license": "BSD", "metadata_version": "2.0", "name": "Jinja2", "run_requires": [{"extra": "i18n", "requires": ["Babel (>=0.8)"]}, {"requires": ["MarkupSafe (>=0.23)"]}], "summary": "A small but fast and easy to use stand-alone template engine written in pure python.", "version": "2.10"}
|
||||
@@ -1 +0,0 @@
|
||||
jinja2
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,33 +0,0 @@
|
||||
`BSD 3-Clause <https://opensource.org/licenses/BSD-3-Clause>`_
|
||||
|
||||
Copyright © 2010 by the Pallets team.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the copyright 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 AND DOCUMENTATION 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
@@ -1,103 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: MarkupSafe
|
||||
Version: 1.1.0
|
||||
Summary: Safely add untrusted strings to HTML/XML markup.
|
||||
Home-page: https://www.palletsprojects.com/p/markupsafe/
|
||||
Author: Armin Ronacher
|
||||
Author-email: armin.ronacher@active-4.com
|
||||
Maintainer: Pallets Team
|
||||
Maintainer-email: contact@palletsprojects.com
|
||||
License: BSD
|
||||
Project-URL: Documentation, https://markupsafe.palletsprojects.com/
|
||||
Project-URL: Code, https://github.com/pallets/markupsafe
|
||||
Project-URL: Issue tracker, https://github.com/pallets/markupsafe/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: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Text Processing :: Markup :: HTML
|
||||
Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
|
||||
|
||||
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('<script>alert(document.cookie);</script>')
|
||||
Markup(u'<script>alert(document.cookie);</script>')
|
||||
>>> # wrap in Markup to mark text "safe" and prevent escaping
|
||||
>>> Markup('<strong>Hello</strong>')
|
||||
Markup('<strong>hello</strong>')
|
||||
>>> escape(Markup('<strong>Hello</strong>'))
|
||||
Markup('<strong>hello</strong>')
|
||||
>>> # Markup is a text subclass (str on Python 3, unicode on Python 2)
|
||||
>>> # methods and operators escape their arguments
|
||||
>>> template = Markup("Hello <em>%s</em>")
|
||||
>>> template % '"World"'
|
||||
Markup('Hello <em>"World"</em>')
|
||||
|
||||
|
||||
Donate
|
||||
------
|
||||
|
||||
The Pallets organization develops and supports MarkupSafe and other
|
||||
libraries that use it. 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://psfmember.org/civicrm/contribute/transact?reset=1&id=20
|
||||
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
* Website: https://www.palletsprojects.com/p/markupsafe/
|
||||
* Documentation: https://markupsafe.palletsprojects.com/
|
||||
* License: `BSD <https://github.com/pallets/markupsafe/blob/master/LICENSE.rst>`_
|
||||
* Releases: https://pypi.org/project/MarkupSafe/
|
||||
* Code: https://github.com/pallets/markupsafe
|
||||
* Issue tracker: https://github.com/pallets/markupsafe/issues
|
||||
* Test status:
|
||||
|
||||
* Linux, Mac: https://travis-ci.org/pallets/markupsafe
|
||||
* Windows: https://ci.appveyor.com/project/pallets/markupsafe
|
||||
|
||||
* Test coverage: https://codecov.io/gh/pallets/markupsafe
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
MarkupSafe-1.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
MarkupSafe-1.1.0.dist-info/LICENSE.txt,sha256=7V249lpOdvRv2m6SF9gCDtq_nsg8tFpdeTdsWWM_g9M,1614
|
||||
MarkupSafe-1.1.0.dist-info/METADATA,sha256=usFnBges7tmAH4_Yt5Ypb8Bco4R9uLUdD0V6YHbvhLw,3585
|
||||
MarkupSafe-1.1.0.dist-info/RECORD,,
|
||||
MarkupSafe-1.1.0.dist-info/WHEEL,sha256=d2ILPScH-y2UwGxsW1PeA2TT-KW0Git4AJ6LeOK8sQo,109
|
||||
MarkupSafe-1.1.0.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
|
||||
markupsafe/__init__.py,sha256=T5J4pS7LRx1xRqfV3xz-QN_D9pSmfVDJnTrc2cTO4Ro,10164
|
||||
markupsafe/__pycache__/__init__.cpython-36.pyc,,
|
||||
markupsafe/__pycache__/_compat.cpython-36.pyc,,
|
||||
markupsafe/__pycache__/_constants.cpython-36.pyc,,
|
||||
markupsafe/__pycache__/_native.cpython-36.pyc,,
|
||||
markupsafe/_compat.py,sha256=3oSvQpEFzsJ29NKVy-Fqk6ZlRxmlCB5k0G21aN0zNtQ,596
|
||||
markupsafe/_constants.py,sha256=ueEz1Jxdw5TKWBbhPr4Ad_2L2MSEh73AYiYe4l3cZy4,4728
|
||||
markupsafe/_native.py,sha256=fUrjjbRXIpHM-8l9QXFJ2xg5rv_48U2aN99plyL0kfs,1911
|
||||
markupsafe/_speedups.c,sha256=VfElhhq9oulHEd2wBZ2MX9A80r4jFovsVGQD2zxmVk0,9883
|
||||
markupsafe/_speedups.cpython-36m-x86_64-linux-gnu.so,sha256=BS7m4DA4L7J_sXAEFkmQeW3HJStGrC1yXYRifVOaTvc,38555
|
||||
@@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.31.1)
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp36-cp36m-manylinux1_x86_64
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
markupsafe
|
||||
@@ -1,33 +0,0 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: PyYAML
|
||||
Version: 3.13
|
||||
Summary: YAML parser and emitter for Python
|
||||
Home-page: http://pyyaml.org/wiki/PyYAML
|
||||
Author: Kirill Simonov
|
||||
Author-email: xi@resolvent.net
|
||||
License: MIT
|
||||
Download-URL: http://pyyaml.org/download/pyyaml/PyYAML-3.13.tar.gz
|
||||
Description: YAML is a data serialization format designed for human readability
|
||||
and interaction with scripting languages. PyYAML is a YAML parser
|
||||
and emitter for Python.
|
||||
|
||||
PyYAML features a complete YAML 1.1 parser, Unicode support, pickle
|
||||
support, capable extension API, and sensible error messages. PyYAML
|
||||
supports standard YAML tags and provides Python-specific tags that
|
||||
allow to represent an arbitrary Python object.
|
||||
|
||||
PyYAML is applicable for a broad range of tasks from complex
|
||||
configuration files to object serialization and persistance.
|
||||
Platform: Any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: 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: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Text Processing :: Markup
|
||||
@@ -1,28 +0,0 @@
|
||||
README
|
||||
setup.cfg
|
||||
setup.py
|
||||
ext/_yaml.c
|
||||
ext/_yaml.h
|
||||
ext/_yaml.pxd
|
||||
ext/_yaml.pyx
|
||||
lib3/PyYAML.egg-info/PKG-INFO
|
||||
lib3/PyYAML.egg-info/SOURCES.txt
|
||||
lib3/PyYAML.egg-info/dependency_links.txt
|
||||
lib3/PyYAML.egg-info/top_level.txt
|
||||
lib3/yaml/__init__.py
|
||||
lib3/yaml/composer.py
|
||||
lib3/yaml/constructor.py
|
||||
lib3/yaml/cyaml.py
|
||||
lib3/yaml/dumper.py
|
||||
lib3/yaml/emitter.py
|
||||
lib3/yaml/error.py
|
||||
lib3/yaml/events.py
|
||||
lib3/yaml/loader.py
|
||||
lib3/yaml/nodes.py
|
||||
lib3/yaml/parser.py
|
||||
lib3/yaml/reader.py
|
||||
lib3/yaml/representer.py
|
||||
lib3/yaml/resolver.py
|
||||
lib3/yaml/scanner.py
|
||||
lib3/yaml/serializer.py
|
||||
lib3/yaml/tokens.py
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
../yaml/__init__.py
|
||||
../yaml/__pycache__/__init__.cpython-36.pyc
|
||||
../yaml/__pycache__/composer.cpython-36.pyc
|
||||
../yaml/__pycache__/constructor.cpython-36.pyc
|
||||
../yaml/__pycache__/cyaml.cpython-36.pyc
|
||||
../yaml/__pycache__/dumper.cpython-36.pyc
|
||||
../yaml/__pycache__/emitter.cpython-36.pyc
|
||||
../yaml/__pycache__/error.cpython-36.pyc
|
||||
../yaml/__pycache__/events.cpython-36.pyc
|
||||
../yaml/__pycache__/loader.cpython-36.pyc
|
||||
../yaml/__pycache__/nodes.cpython-36.pyc
|
||||
../yaml/__pycache__/parser.cpython-36.pyc
|
||||
../yaml/__pycache__/reader.cpython-36.pyc
|
||||
../yaml/__pycache__/representer.cpython-36.pyc
|
||||
../yaml/__pycache__/resolver.cpython-36.pyc
|
||||
../yaml/__pycache__/scanner.cpython-36.pyc
|
||||
../yaml/__pycache__/serializer.cpython-36.pyc
|
||||
../yaml/__pycache__/tokens.cpython-36.pyc
|
||||
../yaml/composer.py
|
||||
../yaml/constructor.py
|
||||
../yaml/cyaml.py
|
||||
../yaml/dumper.py
|
||||
../yaml/emitter.py
|
||||
../yaml/error.py
|
||||
../yaml/events.py
|
||||
../yaml/loader.py
|
||||
../yaml/nodes.py
|
||||
../yaml/parser.py
|
||||
../yaml/reader.py
|
||||
../yaml/representer.py
|
||||
../yaml/resolver.py
|
||||
../yaml/scanner.py
|
||||
../yaml/serializer.py
|
||||
../yaml/tokens.py
|
||||
PKG-INFO
|
||||
SOURCES.txt
|
||||
dependency_links.txt
|
||||
top_level.txt
|
||||
@@ -1,2 +0,0 @@
|
||||
_yaml
|
||||
yaml
|
||||
@@ -1,80 +0,0 @@
|
||||
Werkzeug
|
||||
========
|
||||
|
||||
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 is Unicode aware and 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.
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Install and update using `pip`_:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
pip install -U Werkzeug
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
* Website: https://www.palletsprojects.com/p/werkzeug/
|
||||
* Releases: https://pypi.org/project/Werkzeug/
|
||||
* Code: https://github.com/pallets/werkzeug
|
||||
* Issue tracker: https://github.com/pallets/werkzeug/issues
|
||||
* Test status:
|
||||
|
||||
* Linux, Mac: https://travis-ci.org/pallets/werkzeug
|
||||
* Windows: https://ci.appveyor.com/project/davidism/werkzeug
|
||||
|
||||
* Test coverage: https://codecov.io/gh/pallets/werkzeug
|
||||
|
||||
.. _WSGI: https://wsgi.readthedocs.io/en/latest/
|
||||
.. _Flask: https://www.palletsprojects.com/p/flask/
|
||||
.. _pip: https://pip.pypa.io/en/stable/quickstart/
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,31 +0,0 @@
|
||||
Copyright © 2007 by the Pallets team.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright 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 AND DOCUMENTATION 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
@@ -1,116 +0,0 @@
|
||||
Metadata-Version: 2.0
|
||||
Name: Werkzeug
|
||||
Version: 0.14.1
|
||||
Summary: The comprehensive WSGI web application library.
|
||||
Home-page: https://www.palletsprojects.org/p/werkzeug/
|
||||
Author: Armin Ronacher
|
||||
Author-email: armin.ronacher@active-4.com
|
||||
License: BSD
|
||||
Description-Content-Type: UNKNOWN
|
||||
Platform: any
|
||||
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.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: coverage; extra == 'dev'
|
||||
Requires-Dist: pytest; extra == 'dev'
|
||||
Requires-Dist: sphinx; extra == 'dev'
|
||||
Requires-Dist: tox; extra == 'dev'
|
||||
Provides-Extra: termcolor
|
||||
Requires-Dist: termcolor; extra == 'termcolor'
|
||||
Provides-Extra: watchdog
|
||||
Requires-Dist: watchdog; extra == 'watchdog'
|
||||
|
||||
Werkzeug
|
||||
========
|
||||
|
||||
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 is Unicode aware and 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.
|
||||
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Install and update using `pip`_:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
pip install -U Werkzeug
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
Links
|
||||
-----
|
||||
|
||||
* Website: https://www.palletsprojects.com/p/werkzeug/
|
||||
* Releases: https://pypi.org/project/Werkzeug/
|
||||
* Code: https://github.com/pallets/werkzeug
|
||||
* Issue tracker: https://github.com/pallets/werkzeug/issues
|
||||
* Test status:
|
||||
|
||||
* Linux, Mac: https://travis-ci.org/pallets/werkzeug
|
||||
* Windows: https://ci.appveyor.com/project/davidism/werkzeug
|
||||
|
||||
* Test coverage: https://codecov.io/gh/pallets/werkzeug
|
||||
|
||||
.. _WSGI: https://wsgi.readthedocs.io/en/latest/
|
||||
.. _Flask: https://www.palletsprojects.com/p/flask/
|
||||
.. _pip: https://pip.pypa.io/en/stable/quickstart/
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
Werkzeug-0.14.1.dist-info/DESCRIPTION.rst,sha256=rOCN36jwsWtWsTpqPG96z7FMilB5qI1CIARSKRuUmz8,2452
|
||||
Werkzeug-0.14.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
Werkzeug-0.14.1.dist-info/LICENSE.txt,sha256=xndz_dD4m269AF9l_Xbl5V3tM1N3C1LoZC2PEPxWO-8,1534
|
||||
Werkzeug-0.14.1.dist-info/METADATA,sha256=FbfadrPdJNUWAxMOKxGUtHe5R3IDSBKYYmAz3FvI3uY,3872
|
||||
Werkzeug-0.14.1.dist-info/RECORD,,
|
||||
Werkzeug-0.14.1.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110
|
||||
Werkzeug-0.14.1.dist-info/metadata.json,sha256=4489UTt6HBp2NQil95-pBkjU4Je93SMHvMxZ_rjOpqA,1452
|
||||
Werkzeug-0.14.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9
|
||||
werkzeug/__init__.py,sha256=NR0d4n_-U9BLVKlOISean3zUt2vBwhvK-AZE6M0sC0k,6842
|
||||
werkzeug/__pycache__/__init__.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/_compat.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/_internal.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/_reloader.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/datastructures.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/exceptions.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/filesystem.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/formparser.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/http.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/local.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/posixemulation.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/routing.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/script.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/security.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/serving.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/test.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/testapp.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/urls.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/useragents.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/utils.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/websocket.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/wrappers.cpython-36.pyc,,
|
||||
werkzeug/__pycache__/wsgi.cpython-36.pyc,,
|
||||
werkzeug/_compat.py,sha256=8c4U9o6A_TR9nKCcTbpZNxpqCXcXDVIbFawwKM2s92c,6311
|
||||
werkzeug/_internal.py,sha256=GhEyGMlsSz_tYjsDWO9TG35VN7304MM8gjKDrXLEdVc,13873
|
||||
werkzeug/_reloader.py,sha256=AyPphcOHPbu6qzW0UbrVvTDJdre5WgpxbhIJN_TqzUc,9264
|
||||
werkzeug/contrib/__init__.py,sha256=f7PfttZhbrImqpr5Ezre8CXgwvcGUJK7zWNpO34WWrw,623
|
||||
werkzeug/contrib/__pycache__/__init__.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/atom.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/cache.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/fixers.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/iterio.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/jsrouting.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/limiter.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/lint.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/profiler.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/securecookie.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/sessions.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/testtools.cpython-36.pyc,,
|
||||
werkzeug/contrib/__pycache__/wrappers.cpython-36.pyc,,
|
||||
werkzeug/contrib/atom.py,sha256=qqfJcfIn2RYY-3hO3Oz0aLq9YuNubcPQ_KZcNsDwVJo,15575
|
||||
werkzeug/contrib/cache.py,sha256=xBImHNj09BmX_7kC5NUCx8f_l4L8_O7zi0jCL21UZKE,32163
|
||||
werkzeug/contrib/fixers.py,sha256=gR06T-w71ur-tHQ_31kP_4jpOncPJ4Wc1dOqTvYusr8,10179
|
||||
werkzeug/contrib/iterio.py,sha256=RlqDvGhz0RneTpzE8dVc-yWCUv4nkPl1jEc_EDp2fH0,10814
|
||||
werkzeug/contrib/jsrouting.py,sha256=QTmgeDoKXvNK02KzXgx9lr3cAH6fAzpwF5bBdPNvJPs,8564
|
||||
werkzeug/contrib/limiter.py,sha256=iS8-ahPZ-JLRnmfIBzxpm7O_s3lPsiDMVWv7llAIDCI,1334
|
||||
werkzeug/contrib/lint.py,sha256=Mj9NeUN7s4zIUWeQOAVjrmtZIcl3Mm2yDe9BSIr9YGE,12558
|
||||
werkzeug/contrib/profiler.py,sha256=ISwCWvwVyGpDLRBRpLjo_qUWma6GXYBrTAco4PEQSHY,5151
|
||||
werkzeug/contrib/securecookie.py,sha256=uWMyHDHY3lkeBRiCSayGqWkAIy4a7xAbSE_Hln9ecqc,12196
|
||||
werkzeug/contrib/sessions.py,sha256=39LVNvLbm5JWpbxM79WC2l87MJFbqeISARjwYbkJatw,12577
|
||||
werkzeug/contrib/testtools.py,sha256=G9xN-qeihJlhExrIZMCahvQOIDxdL9NiX874jiiHFMs,2453
|
||||
werkzeug/contrib/wrappers.py,sha256=v7OYlz7wQtDlS9fey75UiRZ1IkUWqCpzbhsLy4k14Hw,10398
|
||||
werkzeug/datastructures.py,sha256=3IgNKNqrz-ZjmAG7y3YgEYK-enDiMT_b652PsypWcYg,90080
|
||||
werkzeug/debug/__init__.py,sha256=uSn9BqCZ5E3ySgpoZtundpROGsn-uYvZtSFiTfAX24M,17452
|
||||
werkzeug/debug/__pycache__/__init__.cpython-36.pyc,,
|
||||
werkzeug/debug/__pycache__/console.cpython-36.pyc,,
|
||||
werkzeug/debug/__pycache__/repr.cpython-36.pyc,,
|
||||
werkzeug/debug/__pycache__/tbtools.cpython-36.pyc,,
|
||||
werkzeug/debug/console.py,sha256=n3-dsKk1TsjnN-u4ZgmuWCU_HO0qw5IA7ttjhyyMM6I,5607
|
||||
werkzeug/debug/repr.py,sha256=bKqstDYGfECpeLerd48s_hxuqK4b6UWnjMu3d_DHO8I,9340
|
||||
werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673
|
||||
werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507
|
||||
werkzeug/debug/shared/debugger.js,sha256=PKPVYuyO4SX1hkqLOwCLvmIEO5154WatFYaXE-zIfKI,6264
|
||||
werkzeug/debug/shared/jquery.js,sha256=7LkWEzqTdpEfELxcZZlS6wAx5Ff13zZ83lYO2_ujj7g,95957
|
||||
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=IEO0PC2pWmh2aEyGCaN--txuWsRCliuhlbEhPDFwh0A,6270
|
||||
werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220
|
||||
werkzeug/debug/tbtools.py,sha256=rBudXCmkVdAKIcdhxANxgf09g6kQjJWW9_5bjSpr4OY,18451
|
||||
werkzeug/exceptions.py,sha256=3wp95Hqj9FqV8MdikV99JRcHse_fSMn27V8tgP5Hw2c,20505
|
||||
werkzeug/filesystem.py,sha256=hHWeWo_gqLMzTRfYt8-7n2wWcWUNTnDyudQDLOBEICE,2175
|
||||
werkzeug/formparser.py,sha256=mUuCwjzjb8_E4RzrAT2AioLuZSYpqR1KXTK6LScRYzA,21722
|
||||
werkzeug/http.py,sha256=RQg4MJuhRv2isNRiEh__Phh09ebpfT3Kuu_GfrZ54_c,40079
|
||||
werkzeug/local.py,sha256=QdQhWV5L8p1Y1CJ1CDStwxaUs24SuN5aebHwjVD08C8,14553
|
||||
werkzeug/posixemulation.py,sha256=xEF2Bxc-vUCPkiu4IbfWVd3LW7DROYAT-ExW6THqyzw,3519
|
||||
werkzeug/routing.py,sha256=2JVtdSgxKGeANy4Z_FP-dKESvKtkYGCZ1J2fARCLGCY,67214
|
||||
werkzeug/script.py,sha256=DwaVDcXdaOTffdNvlBdLitxWXjKaRVT32VbhDtljFPY,11365
|
||||
werkzeug/security.py,sha256=0m107exslz4QJLWQCpfQJ04z3re4eGHVggRvrQVAdWc,9193
|
||||
werkzeug/serving.py,sha256=A0flnIJHufdn2QJ9oeuHfrXwP3LzP8fn3rNW6hbxKUg,31926
|
||||
werkzeug/test.py,sha256=XmECSmnpASiYQTct4oMiWr0LT5jHWCtKqnpYKZd2ui8,36100
|
||||
werkzeug/testapp.py,sha256=3HQRW1sHZKXuAjCvFMet4KXtQG3loYTFnvn6LWt-4zI,9396
|
||||
werkzeug/urls.py,sha256=dUeLg2IeTm0WLmSvFeD4hBZWGdOs-uHudR5-t8n9zPo,36771
|
||||
werkzeug/useragents.py,sha256=BhYMf4cBTHyN4U0WsQedePIocmNlH_34C-UwqSThGCc,5865
|
||||
werkzeug/utils.py,sha256=BrY1j0DHQ8RTb0K1StIobKuMJhN9SQQkWEARbrh2qpk,22972
|
||||
werkzeug/websocket.py,sha256=PpSeDxXD_0UsPAa5hQhQNM6mxibeUgn8lA8eRqiS0vM,11344
|
||||
werkzeug/wrappers.py,sha256=kbyL_aFjxELwPgMwfNCYjKu-CR6kNkh-oO8wv3GXbk8,84511
|
||||
werkzeug/wsgi.py,sha256=1Nob-aeChWQf7MsiicO8RZt6J90iRzEcik44ev9Qu8s,49347
|
||||
@@ -1,6 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.26.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"generator": "bdist_wheel (0.26.0)", "summary": "The comprehensive WSGI web application library.", "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"project_urls": {"Home": "https://www.palletsprojects.org/p/werkzeug/"}, "contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}}}, "license": "BSD", "metadata_version": "2.0", "name": "Werkzeug", "platform": "any", "extras": ["dev", "termcolor", "watchdog"], "run_requires": [{"requires": ["coverage", "pytest", "sphinx", "tox"], "extra": "dev"}, {"requires": ["termcolor"], "extra": "termcolor"}, {"requires": ["watchdog"], "extra": "watchdog"}], "version": "0.14.1"}
|
||||
@@ -1 +0,0 @@
|
||||
werkzeug
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -1,171 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collections import MutableMapping
|
||||
try:
|
||||
from collections import UserDict
|
||||
except ImportError:
|
||||
from UserDict import UserDict
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from ordereddict import OrderedDict
|
||||
|
||||
from io import open
|
||||
import sys
|
||||
try:
|
||||
from thread import get_ident
|
||||
except ImportError:
|
||||
try:
|
||||
from _thread import get_ident
|
||||
except ImportError:
|
||||
from _dummy_thread import get_ident
|
||||
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
str = type('str')
|
||||
|
||||
|
||||
def from_none(exc):
|
||||
"""raise from_none(ValueError('a')) == raise ValueError('a') from None"""
|
||||
exc.__cause__ = None
|
||||
exc.__suppress_context__ = True
|
||||
return exc
|
||||
|
||||
|
||||
# from reprlib 3.2.1
|
||||
def recursive_repr(fillvalue='...'):
|
||||
'Decorator to make a repr function return fillvalue for a recursive call'
|
||||
|
||||
def decorating_function(user_function):
|
||||
repr_running = set()
|
||||
|
||||
def wrapper(self):
|
||||
key = id(self), get_ident()
|
||||
if key in repr_running:
|
||||
return fillvalue
|
||||
repr_running.add(key)
|
||||
try:
|
||||
result = user_function(self)
|
||||
finally:
|
||||
repr_running.discard(key)
|
||||
return result
|
||||
|
||||
# Can't use functools.wraps() here because of bootstrap issues
|
||||
wrapper.__module__ = getattr(user_function, '__module__')
|
||||
wrapper.__doc__ = getattr(user_function, '__doc__')
|
||||
wrapper.__name__ = getattr(user_function, '__name__')
|
||||
wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
|
||||
return wrapper
|
||||
|
||||
return decorating_function
|
||||
|
||||
# from collections 3.2.1
|
||||
class _ChainMap(MutableMapping):
|
||||
''' A ChainMap groups multiple dicts (or other mappings) together
|
||||
to create a single, updateable view.
|
||||
|
||||
The underlying mappings are stored in a list. That list is public and can
|
||||
accessed or updated using the *maps* attribute. There is no other state.
|
||||
|
||||
Lookups search the underlying mappings successively until a key is found.
|
||||
In contrast, writes, updates, and deletions only operate on the first
|
||||
mapping.
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, *maps):
|
||||
'''Initialize a ChainMap by setting *maps* to the given mappings.
|
||||
If no mappings are provided, a single empty dictionary is used.
|
||||
|
||||
'''
|
||||
self.maps = list(maps) or [{}] # always at least one map
|
||||
|
||||
def __missing__(self, key):
|
||||
raise KeyError(key)
|
||||
|
||||
def __getitem__(self, key):
|
||||
for mapping in self.maps:
|
||||
try:
|
||||
return mapping[key] # can't use 'key in mapping' with defaultdict
|
||||
except KeyError:
|
||||
pass
|
||||
return self.__missing__(key) # support subclasses that define __missing__
|
||||
|
||||
def get(self, key, default=None):
|
||||
return self[key] if key in self else default
|
||||
|
||||
def __len__(self):
|
||||
return len(set().union(*self.maps)) # reuses stored hash values if possible
|
||||
|
||||
def __iter__(self):
|
||||
return iter(set().union(*self.maps))
|
||||
|
||||
def __contains__(self, key):
|
||||
return any(key in m for m in self.maps)
|
||||
|
||||
@recursive_repr()
|
||||
def __repr__(self):
|
||||
return '{0.__class__.__name__}({1})'.format(
|
||||
self, ', '.join(map(repr, self.maps)))
|
||||
|
||||
@classmethod
|
||||
def fromkeys(cls, iterable, *args):
|
||||
'Create a ChainMap with a single dict created from the iterable.'
|
||||
return cls(dict.fromkeys(iterable, *args))
|
||||
|
||||
def copy(self):
|
||||
'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]'
|
||||
return self.__class__(self.maps[0].copy(), *self.maps[1:])
|
||||
|
||||
__copy__ = copy
|
||||
|
||||
def new_child(self): # like Django's Context.push()
|
||||
'New ChainMap with a new dict followed by all previous maps.'
|
||||
return self.__class__({}, *self.maps)
|
||||
|
||||
@property
|
||||
def parents(self): # like Django's Context.pop()
|
||||
'New ChainMap from maps[1:].'
|
||||
return self.__class__(*self.maps[1:])
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.maps[0][key] = value
|
||||
|
||||
def __delitem__(self, key):
|
||||
try:
|
||||
del self.maps[0][key]
|
||||
except KeyError:
|
||||
raise KeyError('Key not found in the first mapping: {!r}'.format(key))
|
||||
|
||||
def popitem(self):
|
||||
'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.'
|
||||
try:
|
||||
return self.maps[0].popitem()
|
||||
except KeyError:
|
||||
raise KeyError('No keys found in the first mapping.')
|
||||
|
||||
def pop(self, key, *args):
|
||||
'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].'
|
||||
try:
|
||||
return self.maps[0].pop(key, *args)
|
||||
except KeyError:
|
||||
raise KeyError('Key not found in the first mapping: {!r}'.format(key))
|
||||
|
||||
def clear(self):
|
||||
'Clear maps[0], leaving maps[1:] intact.'
|
||||
self.maps[0].clear()
|
||||
|
||||
|
||||
try:
|
||||
from collections import ChainMap
|
||||
except ImportError:
|
||||
ChainMap = _ChainMap
|
||||
@@ -1,101 +0,0 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: blinker
|
||||
Version: 1.4
|
||||
Summary: Fast, simple object-to-object and broadcast signaling
|
||||
Home-page: http://pythonhosted.org/blinker/
|
||||
Author: Jason Kirtland
|
||||
Author-email: jek@discorporate.us
|
||||
License: MIT License
|
||||
Description: [](https://travis-ci.org/jek/blinker)
|
||||
|
||||
|
||||
# Blinker
|
||||
|
||||
Blinker provides a fast dispatching system that allows any number of
|
||||
interested parties to subscribe to events, or "signals".
|
||||
|
||||
Signal receivers can subscribe to specific senders or receive signals
|
||||
sent by any sender.
|
||||
|
||||
>>> from blinker import signal
|
||||
>>> started = signal('round-started')
|
||||
>>> def each(round):
|
||||
... print "Round %s!" % round
|
||||
...
|
||||
>>> started.connect(each)
|
||||
|
||||
>>> def round_two(round):
|
||||
... print "This is round two."
|
||||
...
|
||||
>>> started.connect(round_two, sender=2)
|
||||
|
||||
>>> for round in range(1, 4):
|
||||
... started.send(round)
|
||||
...
|
||||
Round 1!
|
||||
Round 2!
|
||||
This is round two.
|
||||
Round 3!
|
||||
|
||||
See the [Blinker documentation](https://pythonhosted.org/blinker/) for more information.
|
||||
|
||||
## Requirements
|
||||
|
||||
Blinker requires Python 2.4 or higher, Python 3.0 or higher, or Jython 2.5 or higher.
|
||||
|
||||
## Changelog Summary
|
||||
|
||||
1.3 (July 3, 2013)
|
||||
|
||||
- The global signal stash behind blinker.signal() is now backed by a
|
||||
regular name-to-Signal dictionary. Previously, weak references were
|
||||
held in the mapping and ephemeral usage in code like
|
||||
``signal('foo').connect(...)`` could have surprising program behavior
|
||||
depending on import order of modules.
|
||||
- blinker.Namespace is now built on a regular dict. Use
|
||||
blinker.WeakNamespace for the older, weak-referencing behavior.
|
||||
- Signal.connect('text-sender') uses an alternate hashing strategy to
|
||||
avoid sharp edges in text identity.
|
||||
|
||||
1.2 (October 26, 2011)
|
||||
|
||||
- Added Signal.receiver_connected and Signal.receiver_disconnected
|
||||
per-Signal signals.
|
||||
- Deprecated the global 'receiver_connected' signal.
|
||||
- Verified Python 3.2 support (no changes needed!)
|
||||
|
||||
1.1 (July 21, 2010)
|
||||
|
||||
- Added ``@signal.connect_via(sender)`` decorator
|
||||
- Added ``signal.connected_to`` shorthand name for the
|
||||
``temporarily_connected_to`` context manager.
|
||||
|
||||
1.0 (March 28, 2010)
|
||||
|
||||
- Python 3.x compatibility
|
||||
|
||||
0.9 (February 26, 2010)
|
||||
|
||||
- Sphinx docs, project website
|
||||
- Added ``with a_signal.temporarily_connected_to(receiver): ...`` support
|
||||
|
||||
Keywords: signal emit events broadcast
|
||||
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.4
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.0
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: Utilities
|
||||
@@ -1,49 +0,0 @@
|
||||
AUTHORS
|
||||
CHANGES
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README.md
|
||||
setup.cfg
|
||||
setup.py
|
||||
blinker/__init__.py
|
||||
blinker/_saferef.py
|
||||
blinker/_utilities.py
|
||||
blinker/base.py
|
||||
blinker.egg-info/PKG-INFO
|
||||
blinker.egg-info/SOURCES.txt
|
||||
blinker.egg-info/dependency_links.txt
|
||||
blinker.egg-info/top_level.txt
|
||||
docs/html/genindex.html
|
||||
docs/html/index.html
|
||||
docs/html/objects.inv
|
||||
docs/html/search.html
|
||||
docs/html/searchindex.js
|
||||
docs/html/_sources/index.txt
|
||||
docs/html/_static/basic.css
|
||||
docs/html/_static/blinker-named.png
|
||||
docs/html/_static/blinker64.png
|
||||
docs/html/_static/comment-bright.png
|
||||
docs/html/_static/comment-close.png
|
||||
docs/html/_static/comment.png
|
||||
docs/html/_static/doctools.js
|
||||
docs/html/_static/down-pressed.png
|
||||
docs/html/_static/down.png
|
||||
docs/html/_static/file.png
|
||||
docs/html/_static/flasky.css
|
||||
docs/html/_static/jquery.js
|
||||
docs/html/_static/minus.png
|
||||
docs/html/_static/plus.png
|
||||
docs/html/_static/pygments.css
|
||||
docs/html/_static/searchtools.js
|
||||
docs/html/_static/underscore.js
|
||||
docs/html/_static/up-pressed.png
|
||||
docs/html/_static/up.png
|
||||
docs/html/_static/websupport.js
|
||||
docs/source/conf.py
|
||||
docs/source/index.rst
|
||||
docs/source/_themes/flask_theme_support.py
|
||||
docs/text/index.txt
|
||||
tests/test_context.py
|
||||
tests/test_saferef.py
|
||||
tests/test_signals.py
|
||||
tests/test_utilities.py
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
../blinker/__init__.py
|
||||
../blinker/__pycache__/__init__.cpython-36.pyc
|
||||
../blinker/__pycache__/_saferef.cpython-36.pyc
|
||||
../blinker/__pycache__/_utilities.cpython-36.pyc
|
||||
../blinker/__pycache__/base.cpython-36.pyc
|
||||
../blinker/_saferef.py
|
||||
../blinker/_utilities.py
|
||||
../blinker/base.py
|
||||
PKG-INFO
|
||||
SOURCES.txt
|
||||
dependency_links.txt
|
||||
top_level.txt
|
||||
@@ -1 +0,0 @@
|
||||
blinker
|
||||
@@ -1,22 +0,0 @@
|
||||
from blinker.base import (
|
||||
ANY,
|
||||
NamedSignal,
|
||||
Namespace,
|
||||
Signal,
|
||||
WeakNamespace,
|
||||
receiver_connected,
|
||||
signal,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'ANY',
|
||||
'NamedSignal',
|
||||
'Namespace',
|
||||
'Signal',
|
||||
'WeakNamespace',
|
||||
'receiver_connected',
|
||||
'signal',
|
||||
]
|
||||
|
||||
|
||||
__version__ = '1.4'
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,234 +0,0 @@
|
||||
# extracted from Louie, http://pylouie.org/
|
||||
# updated for Python 3
|
||||
#
|
||||
# Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher,
|
||||
# Matthew R. Scott
|
||||
#
|
||||
# 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 <ORGANIZATION> 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
|
||||
# OWNER 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.
|
||||
#
|
||||
"""Refactored 'safe reference from dispatcher.py"""
|
||||
|
||||
import operator
|
||||
import sys
|
||||
import traceback
|
||||
import weakref
|
||||
|
||||
|
||||
try:
|
||||
callable
|
||||
except NameError:
|
||||
def callable(object):
|
||||
return hasattr(object, '__call__')
|
||||
|
||||
|
||||
if sys.version_info < (3,):
|
||||
get_self = operator.attrgetter('im_self')
|
||||
get_func = operator.attrgetter('im_func')
|
||||
else:
|
||||
get_self = operator.attrgetter('__self__')
|
||||
get_func = operator.attrgetter('__func__')
|
||||
|
||||
|
||||
def safe_ref(target, on_delete=None):
|
||||
"""Return a *safe* weak reference to a callable target.
|
||||
|
||||
- ``target``: The object to be weakly referenced, if it's a bound
|
||||
method reference, will create a BoundMethodWeakref, otherwise
|
||||
creates a simple weakref.
|
||||
|
||||
- ``on_delete``: If provided, will have a hard reference stored to
|
||||
the callable to be called after the safe reference goes out of
|
||||
scope with the reference object, (either a weakref or a
|
||||
BoundMethodWeakref) as argument.
|
||||
"""
|
||||
try:
|
||||
im_self = get_self(target)
|
||||
except AttributeError:
|
||||
if callable(on_delete):
|
||||
return weakref.ref(target, on_delete)
|
||||
else:
|
||||
return weakref.ref(target)
|
||||
else:
|
||||
if im_self is not None:
|
||||
# Turn a bound method into a BoundMethodWeakref instance.
|
||||
# Keep track of these instances for lookup by disconnect().
|
||||
assert hasattr(target, 'im_func') or hasattr(target, '__func__'), (
|
||||
"safe_ref target %r has im_self, but no im_func, "
|
||||
"don't know how to create reference" % target)
|
||||
reference = BoundMethodWeakref(target=target, on_delete=on_delete)
|
||||
return reference
|
||||
|
||||
|
||||
class BoundMethodWeakref(object):
|
||||
"""'Safe' and reusable weak references to instance methods.
|
||||
|
||||
BoundMethodWeakref objects provide a mechanism for referencing a
|
||||
bound method without requiring that the method object itself
|
||||
(which is normally a transient object) is kept alive. Instead,
|
||||
the BoundMethodWeakref object keeps weak references to both the
|
||||
object and the function which together define the instance method.
|
||||
|
||||
Attributes:
|
||||
|
||||
- ``key``: The identity key for the reference, calculated by the
|
||||
class's calculate_key method applied to the target instance method.
|
||||
|
||||
- ``deletion_methods``: Sequence of callable objects taking single
|
||||
argument, a reference to this object which will be called when
|
||||
*either* the target object or target function is garbage
|
||||
collected (i.e. when this object becomes invalid). These are
|
||||
specified as the on_delete parameters of safe_ref calls.
|
||||
|
||||
- ``weak_self``: Weak reference to the target object.
|
||||
|
||||
- ``weak_func``: Weak reference to the target function.
|
||||
|
||||
Class Attributes:
|
||||
|
||||
- ``_all_instances``: Class attribute pointing to all live
|
||||
BoundMethodWeakref objects indexed by the class's
|
||||
calculate_key(target) method applied to the target objects.
|
||||
This weak value dictionary is used to short-circuit creation so
|
||||
that multiple references to the same (object, function) pair
|
||||
produce the same BoundMethodWeakref instance.
|
||||
"""
|
||||
|
||||
_all_instances = weakref.WeakValueDictionary()
|
||||
|
||||
def __new__(cls, target, on_delete=None, *arguments, **named):
|
||||
"""Create new instance or return current instance.
|
||||
|
||||
Basically this method of construction allows us to
|
||||
short-circuit creation of references to already- referenced
|
||||
instance methods. The key corresponding to the target is
|
||||
calculated, and if there is already an existing reference,
|
||||
that is returned, with its deletion_methods attribute updated.
|
||||
Otherwise the new instance is created and registered in the
|
||||
table of already-referenced methods.
|
||||
"""
|
||||
key = cls.calculate_key(target)
|
||||
current = cls._all_instances.get(key)
|
||||
if current is not None:
|
||||
current.deletion_methods.append(on_delete)
|
||||
return current
|
||||
else:
|
||||
base = super(BoundMethodWeakref, cls).__new__(cls)
|
||||
cls._all_instances[key] = base
|
||||
base.__init__(target, on_delete, *arguments, **named)
|
||||
return base
|
||||
|
||||
def __init__(self, target, on_delete=None):
|
||||
"""Return a weak-reference-like instance for a bound method.
|
||||
|
||||
- ``target``: The instance-method target for the weak reference,
|
||||
must have im_self and im_func attributes and be
|
||||
reconstructable via the following, which is true of built-in
|
||||
instance methods::
|
||||
|
||||
target.im_func.__get__( target.im_self )
|
||||
|
||||
- ``on_delete``: Optional callback which will be called when
|
||||
this weak reference ceases to be valid (i.e. either the
|
||||
object or the function is garbage collected). Should take a
|
||||
single argument, which will be passed a pointer to this
|
||||
object.
|
||||
"""
|
||||
def remove(weak, self=self):
|
||||
"""Set self.isDead to True when method or instance is destroyed."""
|
||||
methods = self.deletion_methods[:]
|
||||
del self.deletion_methods[:]
|
||||
try:
|
||||
del self.__class__._all_instances[self.key]
|
||||
except KeyError:
|
||||
pass
|
||||
for function in methods:
|
||||
try:
|
||||
if callable(function):
|
||||
function(self)
|
||||
except Exception:
|
||||
try:
|
||||
traceback.print_exc()
|
||||
except AttributeError:
|
||||
e = sys.exc_info()[1]
|
||||
print ('Exception during saferef %s '
|
||||
'cleanup function %s: %s' % (self, function, e))
|
||||
self.deletion_methods = [on_delete]
|
||||
self.key = self.calculate_key(target)
|
||||
im_self = get_self(target)
|
||||
im_func = get_func(target)
|
||||
self.weak_self = weakref.ref(im_self, remove)
|
||||
self.weak_func = weakref.ref(im_func, remove)
|
||||
self.self_name = str(im_self)
|
||||
self.func_name = str(im_func.__name__)
|
||||
|
||||
def calculate_key(cls, target):
|
||||
"""Calculate the reference key for this reference.
|
||||
|
||||
Currently this is a two-tuple of the id()'s of the target
|
||||
object and the target function respectively.
|
||||
"""
|
||||
return (id(get_self(target)), id(get_func(target)))
|
||||
calculate_key = classmethod(calculate_key)
|
||||
|
||||
def __str__(self):
|
||||
"""Give a friendly representation of the object."""
|
||||
return "%s(%s.%s)" % (
|
||||
self.__class__.__name__,
|
||||
self.self_name,
|
||||
self.func_name,
|
||||
)
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
def __nonzero__(self):
|
||||
"""Whether we are still a valid reference."""
|
||||
return self() is not None
|
||||
|
||||
def __cmp__(self, other):
|
||||
"""Compare with another reference."""
|
||||
if not isinstance(other, self.__class__):
|
||||
return cmp(self.__class__, type(other))
|
||||
return cmp(self.key, other.key)
|
||||
|
||||
def __call__(self):
|
||||
"""Return a strong reference to the bound method.
|
||||
|
||||
If the target cannot be retrieved, then will return None,
|
||||
otherwise returns a bound instance method for our object and
|
||||
function.
|
||||
|
||||
Note: You may call this method any number of times, as it does
|
||||
not invalidate the reference.
|
||||
"""
|
||||
target = self.weak_self()
|
||||
if target is not None:
|
||||
function = self.weak_func()
|
||||
if function is not None:
|
||||
return function.__get__(target)
|
||||
return None
|
||||
@@ -1,163 +0,0 @@
|
||||
from weakref import ref
|
||||
|
||||
from blinker._saferef import BoundMethodWeakref
|
||||
|
||||
|
||||
try:
|
||||
callable
|
||||
except NameError:
|
||||
def callable(object):
|
||||
return hasattr(object, '__call__')
|
||||
|
||||
|
||||
try:
|
||||
from collections import defaultdict
|
||||
except:
|
||||
class defaultdict(dict):
|
||||
|
||||
def __init__(self, default_factory=None, *a, **kw):
|
||||
if (default_factory is not None and
|
||||
not hasattr(default_factory, '__call__')):
|
||||
raise TypeError('first argument must be callable')
|
||||
dict.__init__(self, *a, **kw)
|
||||
self.default_factory = default_factory
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return dict.__getitem__(self, key)
|
||||
except KeyError:
|
||||
return self.__missing__(key)
|
||||
|
||||
def __missing__(self, key):
|
||||
if self.default_factory is None:
|
||||
raise KeyError(key)
|
||||
self[key] = value = self.default_factory()
|
||||
return value
|
||||
|
||||
def __reduce__(self):
|
||||
if self.default_factory is None:
|
||||
args = tuple()
|
||||
else:
|
||||
args = self.default_factory,
|
||||
return type(self), args, None, None, self.items()
|
||||
|
||||
def copy(self):
|
||||
return self.__copy__()
|
||||
|
||||
def __copy__(self):
|
||||
return type(self)(self.default_factory, self)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
import copy
|
||||
return type(self)(self.default_factory,
|
||||
copy.deepcopy(self.items()))
|
||||
|
||||
def __repr__(self):
|
||||
return 'defaultdict(%s, %s)' % (self.default_factory,
|
||||
dict.__repr__(self))
|
||||
|
||||
|
||||
try:
|
||||
from contextlib import contextmanager
|
||||
except ImportError:
|
||||
def contextmanager(fn):
|
||||
def oops(*args, **kw):
|
||||
raise RuntimeError("Python 2.5 or above is required to use "
|
||||
"context managers.")
|
||||
oops.__name__ = fn.__name__
|
||||
return oops
|
||||
|
||||
class _symbol(object):
|
||||
|
||||
def __init__(self, name):
|
||||
"""Construct a new named symbol."""
|
||||
self.__name__ = self.name = name
|
||||
|
||||
def __reduce__(self):
|
||||
return symbol, (self.name,)
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
_symbol.__name__ = 'symbol'
|
||||
|
||||
|
||||
class symbol(object):
|
||||
"""A constant symbol.
|
||||
|
||||
>>> symbol('foo') is symbol('foo')
|
||||
True
|
||||
>>> symbol('foo')
|
||||
foo
|
||||
|
||||
A slight refinement of the MAGICCOOKIE=object() pattern. The primary
|
||||
advantage of symbol() is its repr(). They are also singletons.
|
||||
|
||||
Repeated calls of symbol('name') will all return the same instance.
|
||||
|
||||
"""
|
||||
symbols = {}
|
||||
|
||||
def __new__(cls, name):
|
||||
try:
|
||||
return cls.symbols[name]
|
||||
except KeyError:
|
||||
return cls.symbols.setdefault(name, _symbol(name))
|
||||
|
||||
|
||||
try:
|
||||
text = (str, unicode)
|
||||
except NameError:
|
||||
text = str
|
||||
|
||||
|
||||
def hashable_identity(obj):
|
||||
if hasattr(obj, '__func__'):
|
||||
return (id(obj.__func__), id(obj.__self__))
|
||||
elif hasattr(obj, 'im_func'):
|
||||
return (id(obj.im_func), id(obj.im_self))
|
||||
elif isinstance(obj, text):
|
||||
return obj
|
||||
else:
|
||||
return id(obj)
|
||||
|
||||
|
||||
WeakTypes = (ref, BoundMethodWeakref)
|
||||
|
||||
|
||||
class annotatable_weakref(ref):
|
||||
"""A weakref.ref that supports custom instance attributes."""
|
||||
|
||||
|
||||
def reference(object, callback=None, **annotations):
|
||||
"""Return an annotated weak ref."""
|
||||
if callable(object):
|
||||
weak = callable_reference(object, callback)
|
||||
else:
|
||||
weak = annotatable_weakref(object, callback)
|
||||
for key, value in annotations.items():
|
||||
setattr(weak, key, value)
|
||||
return weak
|
||||
|
||||
|
||||
def callable_reference(object, callback=None):
|
||||
"""Return an annotated weak ref, supporting bound instance methods."""
|
||||
if hasattr(object, 'im_self') and object.im_self is not None:
|
||||
return BoundMethodWeakref(target=object, on_delete=callback)
|
||||
elif hasattr(object, '__self__') and object.__self__ is not None:
|
||||
return BoundMethodWeakref(target=object, on_delete=callback)
|
||||
return annotatable_weakref(object, callback)
|
||||
|
||||
|
||||
class lazy_property(object):
|
||||
"""A @property that is only evaluated once."""
|
||||
|
||||
def __init__(self, deferred):
|
||||
self._deferred = deferred
|
||||
self.__doc__ = deferred.__doc__
|
||||
|
||||
def __get__(self, obj, cls):
|
||||
if obj is None:
|
||||
return self
|
||||
value = self._deferred(obj)
|
||||
setattr(obj, self._deferred.__name__, value)
|
||||
return value
|
||||
@@ -1,455 +0,0 @@
|
||||
# -*- coding: utf-8; fill-column: 76 -*-
|
||||
"""Signals and events.
|
||||
|
||||
A small implementation of signals, inspired by a snippet of Django signal
|
||||
API client code seen in a blog post. Signals are first-class objects and
|
||||
each manages its own receivers and message emission.
|
||||
|
||||
The :func:`signal` function provides singleton behavior for named signals.
|
||||
|
||||
"""
|
||||
from warnings import warn
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
from blinker._utilities import (
|
||||
WeakTypes,
|
||||
contextmanager,
|
||||
defaultdict,
|
||||
hashable_identity,
|
||||
lazy_property,
|
||||
reference,
|
||||
symbol,
|
||||
)
|
||||
|
||||
|
||||
ANY = symbol('ANY')
|
||||
ANY.__doc__ = 'Token for "any sender".'
|
||||
ANY_ID = 0
|
||||
|
||||
|
||||
class Signal(object):
|
||||
"""A notification emitter."""
|
||||
|
||||
#: An :obj:`ANY` convenience synonym, allows ``Signal.ANY``
|
||||
#: without an additional import.
|
||||
ANY = ANY
|
||||
|
||||
@lazy_property
|
||||
def receiver_connected(self):
|
||||
"""Emitted after each :meth:`connect`.
|
||||
|
||||
The signal sender is the signal instance, and the :meth:`connect`
|
||||
arguments are passed through: *receiver*, *sender*, and *weak*.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
"""
|
||||
return Signal(doc="Emitted after a receiver connects.")
|
||||
|
||||
@lazy_property
|
||||
def receiver_disconnected(self):
|
||||
"""Emitted after :meth:`disconnect`.
|
||||
|
||||
The sender is the signal instance, and the :meth:`disconnect` arguments
|
||||
are passed through: *receiver* and *sender*.
|
||||
|
||||
Note, this signal is emitted **only** when :meth:`disconnect` is
|
||||
called explicitly.
|
||||
|
||||
The disconnect signal can not be emitted by an automatic disconnect
|
||||
(due to a weakly referenced receiver or sender going out of scope),
|
||||
as the receiver and/or sender instances are no longer available for
|
||||
use at the time this signal would be emitted.
|
||||
|
||||
An alternative approach is available by subscribing to
|
||||
:attr:`receiver_connected` and setting up a custom weakref cleanup
|
||||
callback on weak receivers and senders.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
"""
|
||||
return Signal(doc="Emitted after a receiver disconnects.")
|
||||
|
||||
def __init__(self, doc=None):
|
||||
"""
|
||||
:param doc: optional. If provided, will be assigned to the signal's
|
||||
__doc__ attribute.
|
||||
|
||||
"""
|
||||
if doc:
|
||||
self.__doc__ = doc
|
||||
#: A mapping of connected receivers.
|
||||
#:
|
||||
#: The values of this mapping are not meaningful outside of the
|
||||
#: internal :class:`Signal` implementation, however the boolean value
|
||||
#: of the mapping is useful as an extremely efficient check to see if
|
||||
#: any receivers are connected to the signal.
|
||||
self.receivers = {}
|
||||
self._by_receiver = defaultdict(set)
|
||||
self._by_sender = defaultdict(set)
|
||||
self._weak_senders = {}
|
||||
|
||||
def connect(self, receiver, sender=ANY, weak=True):
|
||||
"""Connect *receiver* to signal events sent by *sender*.
|
||||
|
||||
:param receiver: A callable. Will be invoked by :meth:`send` with
|
||||
`sender=` as a single positional argument and any \*\*kwargs that
|
||||
were provided to a call to :meth:`send`.
|
||||
|
||||
:param sender: Any object or :obj:`ANY`, defaults to ``ANY``.
|
||||
Restricts notifications delivered to *receiver* to only those
|
||||
:meth:`send` emissions sent by *sender*. If ``ANY``, the receiver
|
||||
will always be notified. A *receiver* may be connected to
|
||||
multiple *sender* values on the same Signal through multiple calls
|
||||
to :meth:`connect`.
|
||||
|
||||
:param weak: If true, the Signal will hold a weakref to *receiver*
|
||||
and automatically disconnect when *receiver* goes out of scope or
|
||||
is garbage collected. Defaults to True.
|
||||
|
||||
"""
|
||||
receiver_id = hashable_identity(receiver)
|
||||
if weak:
|
||||
receiver_ref = reference(receiver, self._cleanup_receiver)
|
||||
receiver_ref.receiver_id = receiver_id
|
||||
else:
|
||||
receiver_ref = receiver
|
||||
if sender is ANY:
|
||||
sender_id = ANY_ID
|
||||
else:
|
||||
sender_id = hashable_identity(sender)
|
||||
|
||||
self.receivers.setdefault(receiver_id, receiver_ref)
|
||||
self._by_sender[sender_id].add(receiver_id)
|
||||
self._by_receiver[receiver_id].add(sender_id)
|
||||
del receiver_ref
|
||||
|
||||
if sender is not ANY and sender_id not in self._weak_senders:
|
||||
# wire together a cleanup for weakref-able senders
|
||||
try:
|
||||
sender_ref = reference(sender, self._cleanup_sender)
|
||||
sender_ref.sender_id = sender_id
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
self._weak_senders.setdefault(sender_id, sender_ref)
|
||||
del sender_ref
|
||||
|
||||
# broadcast this connection. if receivers raise, disconnect.
|
||||
if ('receiver_connected' in self.__dict__ and
|
||||
self.receiver_connected.receivers):
|
||||
try:
|
||||
self.receiver_connected.send(self,
|
||||
receiver=receiver,
|
||||
sender=sender,
|
||||
weak=weak)
|
||||
except:
|
||||
self.disconnect(receiver, sender)
|
||||
raise
|
||||
if receiver_connected.receivers and self is not receiver_connected:
|
||||
try:
|
||||
receiver_connected.send(self,
|
||||
receiver_arg=receiver,
|
||||
sender_arg=sender,
|
||||
weak_arg=weak)
|
||||
except:
|
||||
self.disconnect(receiver, sender)
|
||||
raise
|
||||
return receiver
|
||||
|
||||
def connect_via(self, sender, weak=False):
|
||||
"""Connect the decorated function as a receiver for *sender*.
|
||||
|
||||
:param sender: Any object or :obj:`ANY`. The decorated function
|
||||
will only receive :meth:`send` emissions sent by *sender*. If
|
||||
``ANY``, the receiver will always be notified. A function may be
|
||||
decorated multiple times with differing *sender* values.
|
||||
|
||||
:param weak: If true, the Signal will hold a weakref to the
|
||||
decorated function and automatically disconnect when *receiver*
|
||||
goes out of scope or is garbage collected. Unlike
|
||||
:meth:`connect`, this defaults to False.
|
||||
|
||||
The decorated function will be invoked by :meth:`send` with
|
||||
`sender=` as a single positional argument and any \*\*kwargs that
|
||||
were provided to the call to :meth:`send`.
|
||||
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
"""
|
||||
def decorator(fn):
|
||||
self.connect(fn, sender, weak)
|
||||
return fn
|
||||
return decorator
|
||||
|
||||
@contextmanager
|
||||
def connected_to(self, receiver, sender=ANY):
|
||||
"""Execute a block with the signal temporarily connected to *receiver*.
|
||||
|
||||
:param receiver: a receiver callable
|
||||
:param sender: optional, a sender to filter on
|
||||
|
||||
This is a context manager for use in the ``with`` statement. It can
|
||||
be useful in unit tests. *receiver* is connected to the signal for
|
||||
the duration of the ``with`` block, and will be disconnected
|
||||
automatically when exiting the block:
|
||||
|
||||
.. testsetup::
|
||||
|
||||
from __future__ import with_statement
|
||||
from blinker import Signal
|
||||
on_ready = Signal()
|
||||
receiver = lambda sender: None
|
||||
|
||||
.. testcode::
|
||||
|
||||
with on_ready.connected_to(receiver):
|
||||
# do stuff
|
||||
on_ready.send(123)
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
"""
|
||||
self.connect(receiver, sender=sender, weak=False)
|
||||
try:
|
||||
yield None
|
||||
except:
|
||||
self.disconnect(receiver)
|
||||
raise
|
||||
else:
|
||||
self.disconnect(receiver)
|
||||
|
||||
def temporarily_connected_to(self, receiver, sender=ANY):
|
||||
"""An alias for :meth:`connected_to`.
|
||||
|
||||
:param receiver: a receiver callable
|
||||
:param sender: optional, a sender to filter on
|
||||
|
||||
.. versionadded:: 0.9
|
||||
|
||||
.. versionchanged:: 1.1
|
||||
Renamed to :meth:`connected_to`. ``temporarily_connected_to`` was
|
||||
deprecated in 1.2 and will be removed in a subsequent version.
|
||||
|
||||
"""
|
||||
warn("temporarily_connected_to is deprecated; "
|
||||
"use connected_to instead.",
|
||||
DeprecationWarning)
|
||||
return self.connected_to(receiver, sender)
|
||||
|
||||
def send(self, *sender, **kwargs):
|
||||
"""Emit this signal on behalf of *sender*, passing on \*\*kwargs.
|
||||
|
||||
Returns a list of 2-tuples, pairing receivers with their return
|
||||
value. The ordering of receiver notification is undefined.
|
||||
|
||||
:param \*sender: Any object or ``None``. If omitted, synonymous
|
||||
with ``None``. Only accepts one positional argument.
|
||||
|
||||
:param \*\*kwargs: Data to be sent to receivers.
|
||||
|
||||
"""
|
||||
# Using '*sender' rather than 'sender=None' allows 'sender' to be
|
||||
# used as a keyword argument- i.e. it's an invisible name in the
|
||||
# function signature.
|
||||
if len(sender) == 0:
|
||||
sender = None
|
||||
elif len(sender) > 1:
|
||||
raise TypeError('send() accepts only one positional argument, '
|
||||
'%s given' % len(sender))
|
||||
else:
|
||||
sender = sender[0]
|
||||
if not self.receivers:
|
||||
return []
|
||||
else:
|
||||
return [(receiver, receiver(sender, **kwargs))
|
||||
for receiver in self.receivers_for(sender)]
|
||||
|
||||
def has_receivers_for(self, sender):
|
||||
"""True if there is probably a receiver for *sender*.
|
||||
|
||||
Performs an optimistic check only. Does not guarantee that all
|
||||
weakly referenced receivers are still alive. See
|
||||
:meth:`receivers_for` for a stronger search.
|
||||
|
||||
"""
|
||||
if not self.receivers:
|
||||
return False
|
||||
if self._by_sender[ANY_ID]:
|
||||
return True
|
||||
if sender is ANY:
|
||||
return False
|
||||
return hashable_identity(sender) in self._by_sender
|
||||
|
||||
def receivers_for(self, sender):
|
||||
"""Iterate all live receivers listening for *sender*."""
|
||||
# TODO: test receivers_for(ANY)
|
||||
if self.receivers:
|
||||
sender_id = hashable_identity(sender)
|
||||
if sender_id in self._by_sender:
|
||||
ids = (self._by_sender[ANY_ID] |
|
||||
self._by_sender[sender_id])
|
||||
else:
|
||||
ids = self._by_sender[ANY_ID].copy()
|
||||
for receiver_id in ids:
|
||||
receiver = self.receivers.get(receiver_id)
|
||||
if receiver is None:
|
||||
continue
|
||||
if isinstance(receiver, WeakTypes):
|
||||
strong = receiver()
|
||||
if strong is None:
|
||||
self._disconnect(receiver_id, ANY_ID)
|
||||
continue
|
||||
receiver = strong
|
||||
yield receiver
|
||||
|
||||
def disconnect(self, receiver, sender=ANY):
|
||||
"""Disconnect *receiver* from this signal's events.
|
||||
|
||||
:param receiver: a previously :meth:`connected<connect>` callable
|
||||
|
||||
:param sender: a specific sender to disconnect from, or :obj:`ANY`
|
||||
to disconnect from all senders. Defaults to ``ANY``.
|
||||
|
||||
"""
|
||||
if sender is ANY:
|
||||
sender_id = ANY_ID
|
||||
else:
|
||||
sender_id = hashable_identity(sender)
|
||||
receiver_id = hashable_identity(receiver)
|
||||
self._disconnect(receiver_id, sender_id)
|
||||
|
||||
if ('receiver_disconnected' in self.__dict__ and
|
||||
self.receiver_disconnected.receivers):
|
||||
self.receiver_disconnected.send(self,
|
||||
receiver=receiver,
|
||||
sender=sender)
|
||||
|
||||
def _disconnect(self, receiver_id, sender_id):
|
||||
if sender_id == ANY_ID:
|
||||
if self._by_receiver.pop(receiver_id, False):
|
||||
for bucket in self._by_sender.values():
|
||||
bucket.discard(receiver_id)
|
||||
self.receivers.pop(receiver_id, None)
|
||||
else:
|
||||
self._by_sender[sender_id].discard(receiver_id)
|
||||
self._by_receiver[receiver_id].discard(sender_id)
|
||||
|
||||
def _cleanup_receiver(self, receiver_ref):
|
||||
"""Disconnect a receiver from all senders."""
|
||||
self._disconnect(receiver_ref.receiver_id, ANY_ID)
|
||||
|
||||
def _cleanup_sender(self, sender_ref):
|
||||
"""Disconnect all receivers from a sender."""
|
||||
sender_id = sender_ref.sender_id
|
||||
assert sender_id != ANY_ID
|
||||
self._weak_senders.pop(sender_id, None)
|
||||
for receiver_id in self._by_sender.pop(sender_id, ()):
|
||||
self._by_receiver[receiver_id].discard(sender_id)
|
||||
|
||||
def _cleanup_bookkeeping(self):
|
||||
"""Prune unused sender/receiver bookeeping. Not threadsafe.
|
||||
|
||||
Connecting & disconnecting leave behind a small amount of bookeeping
|
||||
for the receiver and sender values. Typical workloads using Blinker,
|
||||
for example in most web apps, Flask, CLI scripts, etc., are not
|
||||
adversely affected by this bookkeeping.
|
||||
|
||||
With a long-running Python process performing dynamic signal routing
|
||||
with high volume- e.g. connecting to function closures, "senders" are
|
||||
all unique object instances, and doing all of this over and over- you
|
||||
may see memory usage will grow due to extraneous bookeeping. (An empty
|
||||
set() for each stale sender/receiver pair.)
|
||||
|
||||
This method will prune that bookeeping away, with the caveat that such
|
||||
pruning is not threadsafe. The risk is that cleanup of a fully
|
||||
disconnected receiver/sender pair occurs while another thread is
|
||||
connecting that same pair. If you are in the highly dynamic, unique
|
||||
receiver/sender situation that has lead you to this method, that
|
||||
failure mode is perhaps not a big deal for you.
|
||||
"""
|
||||
for mapping in (self._by_sender, self._by_receiver):
|
||||
for _id, bucket in list(mapping.items()):
|
||||
if not bucket:
|
||||
mapping.pop(_id, None)
|
||||
|
||||
def _clear_state(self):
|
||||
"""Throw away all signal state. Useful for unit tests."""
|
||||
self._weak_senders.clear()
|
||||
self.receivers.clear()
|
||||
self._by_sender.clear()
|
||||
self._by_receiver.clear()
|
||||
|
||||
|
||||
receiver_connected = Signal("""\
|
||||
Sent by a :class:`Signal` after a receiver connects.
|
||||
|
||||
:argument: the Signal that was connected to
|
||||
:keyword receiver_arg: the connected receiver
|
||||
:keyword sender_arg: the sender to connect to
|
||||
:keyword weak_arg: true if the connection to receiver_arg is a weak reference
|
||||
|
||||
.. deprecated:: 1.2
|
||||
|
||||
As of 1.2, individual signals have their own private
|
||||
:attr:`~Signal.receiver_connected` and
|
||||
:attr:`~Signal.receiver_disconnected` signals with a slightly simplified
|
||||
call signature. This global signal is planned to be removed in 1.6.
|
||||
|
||||
""")
|
||||
|
||||
|
||||
class NamedSignal(Signal):
|
||||
"""A named generic notification emitter."""
|
||||
|
||||
def __init__(self, name, doc=None):
|
||||
Signal.__init__(self, doc)
|
||||
|
||||
#: The name of this signal.
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
base = Signal.__repr__(self)
|
||||
return "%s; %r>" % (base[:-1], self.name)
|
||||
|
||||
|
||||
class Namespace(dict):
|
||||
"""A mapping of signal names to signals."""
|
||||
|
||||
def signal(self, name, doc=None):
|
||||
"""Return the :class:`NamedSignal` *name*, creating it if required.
|
||||
|
||||
Repeated calls to this function will return the same signal object.
|
||||
|
||||
"""
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return self.setdefault(name, NamedSignal(name, doc))
|
||||
|
||||
|
||||
class WeakNamespace(WeakValueDictionary):
|
||||
"""A weak mapping of signal names to signals.
|
||||
|
||||
Automatically cleans up unused Signals when the last reference goes out
|
||||
of scope. This namespace implementation exists for a measure of legacy
|
||||
compatibility with Blinker <= 1.2, and may be dropped in the future.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
"""
|
||||
|
||||
def signal(self, name, doc=None):
|
||||
"""Return the :class:`NamedSignal` *name*, creating it if required.
|
||||
|
||||
Repeated calls to this function will return the same signal object.
|
||||
|
||||
"""
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return self.setdefault(name, NamedSignal(name, doc))
|
||||
|
||||
|
||||
signal = Namespace().signal
|
||||
@@ -1,97 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
click
|
||||
~~~~~
|
||||
|
||||
Click is a simple Python module inspired by the stdlib optparse to make
|
||||
writing command line scripts fun. Unlike other modules, it's based
|
||||
around a simple API that does not come with too much magic and is
|
||||
composable.
|
||||
|
||||
:copyright: © 2014 by the Pallets team.
|
||||
:license: BSD, see LICENSE.rst for more details.
|
||||
"""
|
||||
|
||||
# Core classes
|
||||
from .core import Context, BaseCommand, Command, MultiCommand, Group, \
|
||||
CommandCollection, Parameter, Option, Argument
|
||||
|
||||
# Globals
|
||||
from .globals import get_current_context
|
||||
|
||||
# Decorators
|
||||
from .decorators import pass_context, pass_obj, make_pass_decorator, \
|
||||
command, group, argument, option, confirmation_option, \
|
||||
password_option, version_option, help_option
|
||||
|
||||
# Types
|
||||
from .types import ParamType, File, Path, Choice, IntRange, Tuple, \
|
||||
DateTime, STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED, FloatRange
|
||||
|
||||
# Utilities
|
||||
from .utils import echo, get_binary_stream, get_text_stream, open_file, \
|
||||
format_filename, get_app_dir, get_os_args
|
||||
|
||||
# Terminal functions
|
||||
from .termui import prompt, confirm, get_terminal_size, echo_via_pager, \
|
||||
progressbar, clear, style, unstyle, secho, edit, launch, getchar, \
|
||||
pause
|
||||
|
||||
# Exceptions
|
||||
from .exceptions import ClickException, UsageError, BadParameter, \
|
||||
FileError, Abort, NoSuchOption, BadOptionUsage, BadArgumentUsage, \
|
||||
MissingParameter
|
||||
|
||||
# Formatting
|
||||
from .formatting import HelpFormatter, wrap_text
|
||||
|
||||
# Parsing
|
||||
from .parser import OptionParser
|
||||
|
||||
|
||||
__all__ = [
|
||||
# Core classes
|
||||
'Context', 'BaseCommand', 'Command', 'MultiCommand', 'Group',
|
||||
'CommandCollection', 'Parameter', 'Option', 'Argument',
|
||||
|
||||
# Globals
|
||||
'get_current_context',
|
||||
|
||||
# Decorators
|
||||
'pass_context', 'pass_obj', 'make_pass_decorator', 'command', 'group',
|
||||
'argument', 'option', 'confirmation_option', 'password_option',
|
||||
'version_option', 'help_option',
|
||||
|
||||
# Types
|
||||
'ParamType', 'File', 'Path', 'Choice', 'IntRange', 'Tuple',
|
||||
'DateTime', 'STRING', 'INT', 'FLOAT', 'BOOL', 'UUID', 'UNPROCESSED',
|
||||
'FloatRange',
|
||||
|
||||
# Utilities
|
||||
'echo', 'get_binary_stream', 'get_text_stream', 'open_file',
|
||||
'format_filename', 'get_app_dir', 'get_os_args',
|
||||
|
||||
# Terminal functions
|
||||
'prompt', 'confirm', 'get_terminal_size', 'echo_via_pager',
|
||||
'progressbar', 'clear', 'style', 'unstyle', 'secho', 'edit', 'launch',
|
||||
'getchar', 'pause',
|
||||
|
||||
# Exceptions
|
||||
'ClickException', 'UsageError', 'BadParameter', 'FileError',
|
||||
'Abort', 'NoSuchOption', 'BadOptionUsage', 'BadArgumentUsage',
|
||||
'MissingParameter',
|
||||
|
||||
# Formatting
|
||||
'HelpFormatter', 'wrap_text',
|
||||
|
||||
# Parsing
|
||||
'OptionParser',
|
||||
]
|
||||
|
||||
|
||||
# Controls if click should emit the warning about the use of unicode
|
||||
# literals.
|
||||
disable_unicode_literals_warning = False
|
||||
|
||||
|
||||
__version__ = '7.0'
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user