diff --git a/2017-04-2-4/modules/1.txt b/2017-04-2-4/modules/1.txt deleted file mode 100644 index 3b18e51..0000000 --- a/2017-04-2-4/modules/1.txt +++ /dev/null @@ -1 +0,0 @@ -hello world diff --git a/2017-04-2-4/modules/alias_module.py b/2017-04-2-4/modules/alias_module.py deleted file mode 100644 index 6781540..0000000 --- a/2017-04-2-4/modules/alias_module.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -' a est module ' -__author__='Kangxiaoxiao' - -try: - import cStringIO as StringIO -except ImportError: # 导入失败会捕获到ImportError - import StringIO diff --git a/2017-04-2-4/modules/helloModule.py b/2017-04-2-4/modules/helloModule.py deleted file mode 100644 index 254af69..0000000 --- a/2017-04-2-4/modules/helloModule.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -' a est module ' -__author__='Kangxiaoxiao' - -import sys -def test(): - args=sys.argv - if len(args)==1: - print 'Hello,world!' - elif len(args)==2: - print 'Hello,%s!' % args[1] - else: - print 'Too many arguments!' -if __name__=='__main__': - test() diff --git a/2017-04-2-4/modules/helloModule.pyc b/2017-04-2-4/modules/helloModule.pyc deleted file mode 100644 index 50b673c..0000000 Binary files a/2017-04-2-4/modules/helloModule.pyc and /dev/null differ diff --git a/2017-04-2-4/modules/read1.py b/2017-04-2-4/modules/read1.py deleted file mode 100644 index 8ea8e51..0000000 --- a/2017-04-2-4/modules/read1.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -try: - f=open('/root/python1/python_execise/2017-04-2-4/modules/1.txt','r') - print f.read() -finally: - if f: - f.close() - diff --git a/2017-04-2-4/operata_file/print_os.py b/2017-04-2-4/operata_file/print_os.py deleted file mode 100644 index 6d7cffe..0000000 --- a/2017-04-2-4/operata_file/print_os.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import os -print os.name diff --git a/2017-04-2-4/operata_file/print_os_name.py b/2017-04-2-4/operata_file/print_os_name.py deleted file mode 100644 index 60641f0..0000000 --- a/2017-04-2-4/operata_file/print_os_name.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import os -print os.uname() diff --git a/2017-04-20/advanced/advanced.py b/2017-04-20/advanced/advanced.py deleted file mode 100644 index 9b61e86..0000000 --- a/2017-04-20/advanced/advanced.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*-i - -L=['AA','FF','EE','RR','WW'] -r=[] - -n=3 -for i in range(n): - r.append(L[i]) - -#print f -#切片操作 Slice 通过: 实现L[0:3]表示,从索引0开始,一直到索引3 -#为止,但不包含索引3,即索引0,1,2, 正好是3,个元素。 -print L -print 'L[0:3]--',L[0:3] # 取索引为 0,1,2 -print 'L[:3]--',L[:3] -print 'L[1:3]--',L[1:3] - -print 'L[-1]--',L[-1] -print 'L[-2:]--',L[-2:] - -print 'L[-2:-1]--',L[-2:-1] - -''' -''' diff --git "a/2017-04-20/advanced/\345\205\203\347\273\204\347\232\204\345\210\207\347\211\207\346\223\215\344\275\234.py" "b/2017-04-20/advanced/\345\205\203\347\273\204\347\232\204\345\210\207\347\211\207\346\223\215\344\275\234.py" deleted file mode 100644 index 9b61e86..0000000 --- "a/2017-04-20/advanced/\345\205\203\347\273\204\347\232\204\345\210\207\347\211\207\346\223\215\344\275\234.py" +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*-i - -L=['AA','FF','EE','RR','WW'] -r=[] - -n=3 -for i in range(n): - r.append(L[i]) - -#print f -#切片操作 Slice 通过: 实现L[0:3]表示,从索引0开始,一直到索引3 -#为止,但不包含索引3,即索引0,1,2, 正好是3,个元素。 -print L -print 'L[0:3]--',L[0:3] # 取索引为 0,1,2 -print 'L[:3]--',L[:3] -print 'L[1:3]--',L[1:3] - -print 'L[-1]--',L[-1] -print 'L[-2:]--',L[-2:] - -print 'L[-2:-1]--',L[-2:-1] - -''' -''' diff --git a/2017-04-20/decorate/decorate.py b/2017-04-20/decorate/decorate.py deleted file mode 100644 index ee30600..0000000 --- a/2017-04-20/decorate/decorate.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import functools -def now(): - print '2017-04-20' -f = now -f() #函数也是一个对象,函数对象可以赋值给变量,通过变量也能调用该函数 - -#函数对象有一个__name__属性,可以拿到函数的名字:双下划线 - -print now.__name__ -print f.__name__ -#本质上,decorator 就是一个返回函数的高阶函数 -def log(func): - @functools.wraps(func) #将原始函数属性复制到wrapper中。 - def wrapper(*args,**kw): - print "call %s()"%func.__name__ - return func(*args, **kw) - return wrapper - -#使用Python的@语法, 在每个函数上使用。 - -@log -def test1(): - print "Hello python..." -test1() - -# equals test1 = log(test1) - -#wrapper() 函数的参数定义是(*args,**kw),因此,wrapper()函数可以接受任意参数的调用,在wrapper()函数内, -#首先打印日志, 再紧接着调用原始函数。 - - -#如果decorator 本身需要传入参数,那就需要编写一个返回decorator的高阶函数。 - -def log2(text): - def decorator(func): - @functools.wraps(func) - def wrapper(*args,**kw): - print '%s %s():' %(text, func.__name__) - return func(*args,**kw) - return wrapper - return decorator - -@log2("text------") -def now2(): - print '2014-11-8' -now2() -print now2.__name__ -#原理解析 now = log2('execute')(now) - -#我们来剖析上面的语句,首先执行log2('execute'),返回的是decorator函数,再调用返回的函数,参数是now -#函数,返回值最终wrapper函数。 -#但是返回的函数, 已经变成了 wrapper diff --git a/2017-04-20/dict/dictdemo.py b/2017-04-20/dict/dictdemo.py deleted file mode 100644 index a11fdc7..0000000 --- a/2017-04-20/dict/dictdemo.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -''' -dict 是用空间换取时间的方法, key 必须是不可变对象 - -set 也是一组key的集合,但是不存储value在set中没有重复的key, 要创建set -需要提供一个list作为输入集合。 -''' -d={'Sean':22,'Mirs':55,'Tom':66} - -print d['Mirs'] -d['Zming'] = 35 -print d - -if 'Mirs' in d: - print d['Mirs'] - -print d.get('Mits') -print d.get('Mits',-1) #不存在时自己指定值。 -#pop(key)删除对应的key 对应的values也会从dict中删除 -d.pop('Mirs') #删除不存在的key时也会报错 - -s = set([1,1,2,3,3,3,3]) #重复元素会自动过滤。 - -print s -s.add(9) -s.remove(1) -print s diff --git a/2017-04-20/if_structure/ifdemo.py b/2017-04-20/if_structure/ifdemo.py deleted file mode 100644 index 3520cb9..0000000 --- a/2017-04-20/if_structure/ifdemo.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -#这里可以输入中文呀。 -age=23 -if age > 18: - print 'your age is ',age - print 'adult' -elif age >6: - print 'your age is ',age - print 'teenager' -else: - print 'kid' - -if True: - print "i am True" diff --git a/2017-04-20/list_execise/.iteration.py.swp b/2017-04-20/list_execise/.iteration.py.swp deleted file mode 100644 index b01a68e..0000000 Binary files a/2017-04-20/list_execise/.iteration.py.swp and /dev/null differ diff --git a/2017-04-20/list_execise/iteration.py b/2017-04-20/list_execise/iteration.py deleted file mode 100644 index 7efcdd8..0000000 --- a/2017-04-20/list_execise/iteration.py +++ /dev/null @@ -1,67 +0,0 @@ -G# -*- coding:utf-8 -*- - -d = {'a':1,'b':2,'c':3} - -for key in d: #打印结果并不是按写的顺序, 默认迭代key - print key - - #迭代 value - -for value in d.itervalues(): - print value - -for k,v in d.iteritems(): - print k,',',v -for ch in 'ABC': - print ch - - #判断对象是否可迭代 - -from collections import Iterable - -print isinstance('abc',Iterable) -#整数不可迭代 -#list实现, java类似的下表循环, 使用内置函数enumrate - -for i,value in enumerate(['A','B','C']): - print i,value - -#在Python 中同时迭代两个值是非常常见的 -for x,y in [(1,1),(2,4),(3,9)]: - print x,y -#列表生产式: 内置 用来创建list的生成式 -print range(1,11) - -#但是要生成[1x1,2x2,...]时怎么办1,循环L.append(ixi) 2, 列表生成式 - -print [x*x for x in range(1,11)] - -#写列表生成式式, 把要生成的元素x*x放到前面, 后面跟for 循环。 -# for 循环后面还可以加上if判断, 这样我们就可以筛选出仅偶数的平方: -print [x*x for x in range(1,11) if x%2==0] -print [m+n for m in 'ABC' for n in 'XYZ'] #双重循环生成全排列。 - -#列表生成式样也可以使用两个参数。 -d = {'x':'A','y':'B','z':'C'} - -print [k+'='+v for k,v in d.iteritems()] - -L = ['Hello','World','IBM','Apple' ] -print [s.lower() for s in L ] - -print isinstance(1,str) #判断是否式字符串。 - - -嵌套的列表可以拆开 -p = ['asp','php'] -s = ['python', 'java',p,'scheme'] - - p = ['asp','php'] ->>> s = ['python', 'java', p, 'scheme'] ->>> p[1] -'php' - -tuple -另一种有序列表叫元组,: tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样的列出同学的名字。 - -classmate = ('Michael','bob','Tracy') diff --git a/2017-04-20/loop_structure/loopdemo.py b/2017-04-20/loop_structure/loopdemo.py deleted file mode 100644 index 39ef39d..0000000 --- a/2017-04-20/loop_structure/loopdemo.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- - -#测测能用中文吗 - -#声明一个列表 - -names = ['Sean','Mirs','Index'] - -for name in names: - print name - -sum = 0 -for x in range(101): - sum = sum+x - -print sum - -sum =0 -n=99 -while n>0: - sum = sum + n - n = n - 2 - -print sum - -#raw_input()读取的内容永远以字符串的形式返回,如果为int需要使用int('str') diff --git a/2017-04-20/oops/oop1.py b/2017-04-20/oops/oop1.py deleted file mode 100644 index 3579d8e..0000000 --- a/2017-04-20/oops/oop1.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -#这个可以有中文了呀 - -__author__ = 'Administrator' - -class Student(object): - def __init__(self,name,score): - self.name = name - self.score = score - - def print_score(self): - print('%s %s'%(self.name,self.score)) - - def get_grade(self): - if self.score >= 90: - return 'A' - elif self.score >= 60: - return 'B' - else: - return 'C' - -bart = Student('Sean',33) - -mirs = Student('mirs',90) - -bart.print_score() -print bart.get_grade() -mirs.print_score() -mirs.score = 30 - -print mirs.get_grade() -#在创建实例的时候, 把一些我们认为必须的属性强制填写进去, 通过定议一个特殊的__init__方法,在 -#创建实例的时候, 就把name,score等属性绑上去。 - -#访问限制 属性前 双 下划线 -class User(object): - def __init__(self,name): - self.__name = name - - def print_name(self): - print "name is %s" %self.__name - - def get_name(self): - return self.__name - -user = User("Tom") -user.print_name() -#print user.__name 不可以访问 - -print user.get_name() #通过get和set方法, 可以对参数做检查。 - -# 其实是可以访问的。 - -print user._User__name #但是强烈不建议你这样做 -#总的来说就是, Python 本身没有任何机制阻止你干坏事,一切全靠自觉。 - -#继承和多态。 - - diff --git a/2017-04-20/string_execise/str_format/form_hellp.py b/2017-04-20/string_execise/str_format/form_hellp.py deleted file mode 100644 index 3731cd8..0000000 --- a/2017-04-20/string_execise/str_format/form_hellp.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -str = '张琰考上了研究生,好呀' -print str diff --git a/2017-04-20/string_execise/str_format/format3.py b/2017-04-20/string_execise/str_format/format3.py deleted file mode 100644 index fe63c05..0000000 --- a/2017-04-20/string_execise/str_format/format3.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -#-*- coding:utf-8 -*- -print '%2d-%02d' % (3,1) -print '%.2f' % 3.1415926 -print 'Age:%s. Gender:%s' % (25,True) -#对于Unicode字符串,用法完全一样,但最好确保替换的字符串也是Unicade字符串。 -print u'Hi, %s' % u'Michael' -#有时候,字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%: -print 'growth rate: %d %%' % 7 diff --git a/2017-04-20/string_execise/str_format/format_hello.py b/2017-04-20/string_execise/str_format/format_hello.py deleted file mode 100644 index 92465db..0000000 --- a/2017-04-20/string_execise/str_format/format_hello.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- - -#测试中文问题。 - -#编写有格式的字符串。 -print 'Hi %s,your score is %d.' %('Bart',59) -print 'Hello,%s' % 'world' -print 'Hi, %s, you have $%d.' % ('Michael',1000000) diff --git "a/2017-04-20/string_execise/str_format/python\345\255\227\347\254\246\344\270\262.txt" "b/2017-04-20/string_execise/str_format/python\345\255\227\347\254\246\344\270\262.txt" deleted file mode 100644 index 169dbca..0000000 --- "a/2017-04-20/string_execise/str_format/python\345\255\227\347\254\246\344\270\262.txt" +++ /dev/null @@ -1,4 +0,0 @@ -%d 整数 -%f 浮点数。 -%s 字符串 -%x 十六进制整数 diff --git a/2017-04-20/string_execise/unicode_and_chinese_str/chinese.py b/2017-04-20/string_execise/unicode_and_chinese_str/chinese.py deleted file mode 100644 index 2ec129f..0000000 --- a/2017-04-20/string_execise/unicode_and_chinese_str/chinese.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -c = '康晓与' -u = u'康小与' -print c -print u diff --git "a/2017-04-20/string_execise/\345\255\227\347\254\246\344\270\262\347\232\204\345\243\260\346\230\216/string1.py" "b/2017-04-20/string_execise/\345\255\227\347\254\246\344\270\262\347\232\204\345\243\260\346\230\216/string1.py" deleted file mode 100644 index bf163a6..0000000 --- "a/2017-04-20/string_execise/\345\255\227\347\254\246\344\270\262\347\232\204\345\243\260\346\230\216/string1.py" +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/env python -str='I want to learn python' -print str diff --git a/2017-04-20/tuple_abc/sliceFib.py b/2017-04-20/tuple_abc/sliceFib.py deleted file mode 100644 index c6bf8e3..0000000 --- a/2017-04-20/tuple_abc/sliceFib.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -__author__ = '康晓宇' - -class Fib(object): - def __getitem__(self,item): - if isinstance(item,int): - a,b=1,1 - for x in range(item): - a,b = b, a+b - return n - - if isinstance(item,slice): - start = item.start - stop = item.stop - a,b = 1,1 - - L = [] - - for x in range(stop): - if x >= start: - L.append(a) - a,b = b, a+b - return L -f = Fib() - -#print f[5:10] - -class Student(object): - def __init__(self): - self.name = "Mirs" - - def __getattr__(self,item): - if item == 'score': - return 99 - if item == 'age': - return lambda:25 - - def __call__(self): - print("My name is %s..."%self.name) -ss = Student() -print ss.score -print ss.age() - -#---------------__call__------------------ -#instance,method, 可不可以, 类似于 instance()本身上调用呢, 在Python中, 是肯定的 - -#只要定义一个__call__() 就可以多实例进行调用 - -ss() diff --git a/2017-04-20/tuple_abc/tuple1.py b/2017-04-20/tuple_abc/tuple1.py deleted file mode 100644 index 222d90e..0000000 --- a/2017-04-20/tuple_abc/tuple1.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- - -classmates=(u'涂金龙',u'康晓宇',u'朱树娜') - -print classmates -print classmates[0] - -t=(1,2) -print t - -t=() -print t - -t=(1,) -print t - -t=('a','b',['A','B']) -print t -t[2][0]='C' - -print t - diff --git a/2017-04-21/decorate.py b/2017-04-21/decorate.py deleted file mode 100644 index 34deedd..0000000 --- a/2017-04-21/decorate.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/env python - - -# -*- coding:utf-8 -*- - -def log(func): - def wrapper(*args,**kw): - print('call %s():' % func.__name__) - return func(*args,**kw) - return wrapper -@log -def now(): - print('2017-04-21') -now() - diff --git a/2017-04-21/for1list.py b/2017-04-21/for1list.py deleted file mode 100644 index 288ee4b..0000000 --- a/2017-04-21/for1list.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -#! -*- coding:utf-8 -*- -#这里可以写中文。 -print [x * x for x in range(1,11) if x %2 == 0] diff --git a/2017-04-21/for2list.py b/2017-04-21/for2list.py deleted file mode 100644 index c85589d..0000000 --- a/2017-04-21/for2list.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -#! -*- coding:utf-8 -*- -#这里可以写中文。 -print [x*x for x in range(1,11) if x % 2 == 0] diff --git a/2017-04-21/for3list.py b/2017-04-21/for3list.py deleted file mode 100644 index 64b213f..0000000 --- a/2017-04-21/for3list.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -#! -*- coding:utf-8 -*- -#这里可以写中文。 -print [m + n for m in 'ABC' for n in 'XYZ'] diff --git a/2017-04-21/for4list.py b/2017-04-21/for4list.py deleted file mode 100644 index 4613044..0000000 --- a/2017-04-21/for4list.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import os -print [d for d in os.listdir('.')] diff --git a/2017-04-21/for5list.py b/2017-04-21/for5list.py deleted file mode 100644 index 566ebf3..0000000 --- a/2017-04-21/for5list.py +++ /dev/null @@ -1,4 +0,0 @@ -d = {'x':'A','y':'B','z':'C'} -for k,v in d.items(): - print(k, '=', v) - diff --git a/2017-04-21/for6list.py b/2017-04-21/for6list.py deleted file mode 100644 index 9b321f0..0000000 --- a/2017-04-21/for6list.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -d = {'x':'A','y':'B','z':'c'} -print [k +'=' + v for k,v in d.items()] diff --git a/2017-04-21/forlist.py b/2017-04-21/forlist.py deleted file mode 100644 index eb2064b..0000000 --- a/2017-04-21/forlist.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -#! -*- coding:utf-8 -*- -#这里可以写中文。 -L = [] -for x in range(1,11): - L.append(x*x) - -print L diff --git a/2017-04-21/func_call.py b/2017-04-21/func_call.py deleted file mode 100644 index c001b2b..0000000 --- a/2017-04-21/func_call.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -#according function to make type transfer -a1 = int('123') -print type(a1) diff --git a/2017-04-21/iterate.py b/2017-04-21/iterate.py deleted file mode 100644 index 5b417dc..0000000 --- a/2017-04-21/iterate.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from collections import Iterable -for i, value in enumerate(['A', 'B', 'C']): - print(i,value) diff --git a/2017-04-21/iterate.txt b/2017-04-21/iterate.txt deleted file mode 100644 index bb6c387..0000000 --- a/2017-04-21/iterate.txt +++ /dev/null @@ -1,17 +0,0 @@ -最后一个小问题,如果要对list实现类似Java那样的下标循环怎么办? - Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身。 -for i,value in enumerate(['A','B','C']): - print(i,value) - -for x,y in [(1,1),(2,4),(3,9)]: - print(x,y) - -for x,y in [(1,1),(2,4),(3,9)]: -... print(x,y) -... -(1, 1) -(2, 4) -(3, 9) - -任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。 - diff --git a/2017-04-21/my_abs.py b/2017-04-21/my_abs.py deleted file mode 100644 index 7493aec..0000000 --- a/2017-04-21/my_abs.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -print u'函数的自定义' -def my_abs(x): - if x >= 0: - return x - else: - return -x -re1 = my_abs(-9) -print re1 -re2 = my_abs(2) -print re2 diff --git a/2017-04-21/my_abs.txt b/2017-04-21/my_abs.txt deleted file mode 100644 index 66120c4..0000000 --- a/2017-04-21/my_abs.txt +++ /dev/null @@ -1,8 +0,0 @@ -函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回,因此,函数内部通过条件 -判断和循环非常复杂的逻辑。 -如果没有return语句, 函数执行完毕后也会返回结果, 只是结果为None. -return None可以简写为return. -在Python交互环境中定义函数时,注意Python会出现的提示。 -(函数定义结束后需要按两次回车重新回到>>>提示符下。) -在Python shell中函数可以被删除i -del my_abs diff --git a/2017-04-21/str_low.py b/2017-04-21/str_low.py deleted file mode 100644 index ba4215f..0000000 --- a/2017-04-21/str_low.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -L = ['Hello','World','IBM','Apple'] -print [s.lower() for s in L] diff --git a/2017-04-21/test1.py b/2017-04-21/test1.py deleted file mode 100644 index 556a3b3..0000000 --- a/2017-04-21/test1.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -L=[] -n=1 -while n <=99: - L.append(n) - n = n +2 -print L diff --git "a/2017-04-21/\345\210\227\350\241\250\347\224\237\346\210\220\345\274\217.txt" "b/2017-04-21/\345\210\227\350\241\250\347\224\237\346\210\220\345\274\217.txt" deleted file mode 100644 index 03e44db..0000000 --- "a/2017-04-21/\345\210\227\350\241\250\347\224\237\346\210\220\345\274\217.txt" +++ /dev/null @@ -1,7 +0,0 @@ -列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的 -生成式。 -举个例子, 要生成list[1,2,3,--10],可以用list(range(1,11))\ -list(range(1,11)) - -list(range(1,11)) -[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] diff --git "a/2017-04-21/\351\253\230\351\230\266\347\211\271\346\200\247\343\200\202txt" "b/2017-04-21/\351\253\230\351\230\266\347\211\271\346\200\247\343\200\202txt" deleted file mode 100644 index 92af553..0000000 --- "a/2017-04-21/\351\253\230\351\230\266\347\211\271\346\200\247\343\200\202txt" +++ /dev/null @@ -1,10 +0,0 @@ -L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。 - -如果第一个索引是0,还可以省略: - ->>> L[:3] -['Michael', 'Sarah', 'Tracy'] - -检查是否可以迭代 -from collectons import Iterable -isinstance('abc',Iterable) diff --git a/2017-04-24/diedaiqi/odd_g.py b/2017-04-24/diedaiqi/odd_g.py deleted file mode 100644 index 1783417..0000000 --- a/2017-04-24/diedaiqi/odd_g.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -#这里,最难理解的就是generator和函数的执行流程不一样。 -#函数是顺序执行,遇到return语句或者最后一行函数语句就返回。i -#而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。 -def odd(): - print 'step 1' - yield 1 - print 'step 2' - yield 3 - print 'step 3' - yield 5 -o = odd() -print o.next() -print o.next() -print o.next() diff --git a/2017-04-24/diedaiqi/triangle.py b/2017-04-24/diedaiqi/triangle.py deleted file mode 100644 index 3541263..0000000 --- a/2017-04-24/diedaiqi/triangle.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -#我爱中文 -def fib(max): - n,a,b=0,0,1 - while n < max: - yield b - a,b=b,a+b - n=n+1 -print fib(6) diff --git a/2017-04-24/filter/filter_empty.py b/2017-04-24/filter/filter_empty.py deleted file mode 100644 index 468e5fc..0000000 --- a/2017-04-24/filter/filter_empty.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def not_empty(s): - return s and s.strip() -print filter(not_empty,['A','','B',None,'C','']) diff --git a/2017-04-24/filter/filter_odd.py b/2017-04-24/filter/filter_odd.py deleted file mode 100644 index 4a49496..0000000 --- a/2017-04-24/filter/filter_odd.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def is_odd(n): - return n%2 == 1 - -print filter(is_odd,[1,2,4,5,6,9,10,15]) diff --git a/2017-04-24/generator/generator2.py b/2017-04-24/generator/generator2.py deleted file mode 100644 index 61cc343..0000000 --- a/2017-04-24/generator/generator2.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -L=[x*x for x in range(10)] -print L -g=(x*x for x in range(10)) -print g -#建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。 - -#我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢? - -#如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值: -for n in g: - print(n) diff --git a/2017-04-24/generator/generator2_error.py b/2017-04-24/generator/generator2_error.py deleted file mode 100644 index 4e6cb1a..0000000 --- a/2017-04-24/generator/generator2_error.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -L=[x*x for x in range(10)] -print L -g=(x*x for x in range(10)) -print g -#建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。 - -#我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢? - -#如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值: - -next(g) -next(g) -next(g) -next(g) -next(g) -next(g) -next(g) -next(g) -next(g) -next(g) -next(g) diff --git a/2017-04-24/high_grade_feature/odd.py b/2017-04-24/high_grade_feature/odd.py deleted file mode 100644 index 4635e9a..0000000 --- a/2017-04-24/high_grade_feature/odd.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -L=[] -n=1 -while n <=99: - L.append(n) - n=n+2 -print L diff --git a/2017-04-24/high_order/high1.py b/2017-04-24/high_order/high1.py deleted file mode 100644 index ce427c7..0000000 --- a/2017-04-24/high_order/high1.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -#-*- coding:utf-8 -*- -#那么函数名是什么呢?函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数! - -#如果把abs指向其他对象,会有什么情况发生? - -abs = 10 -print abs(-10) diff --git a/2017-04-24/high_order/map_first.py b/2017-04-24/high_order/map_first.py deleted file mode 100644 index 6bea7d4..0000000 --- a/2017-04-24/high_order/map_first.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def f(x): - return x * x -print map(f,[1,2,3,4,5,6,7,8,9]) diff --git a/2017-04-24/high_order/transfer_func.py b/2017-04-24/high_order/transfer_func.py deleted file mode 100644 index 50fba60..0000000 --- a/2017-04-24/high_order/transfer_func.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def add(x,y,f): - return f(x) + f(y) -print add(-5,6,abs) -#把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式 diff --git a/2017-04-24/itera/for_2_variable.py b/2017-04-24/itera/for_2_variable.py deleted file mode 100644 index ef75868..0000000 --- a/2017-04-24/itera/for_2_variable.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from collections import Iterable -for x,y in [(1,1),(2,4),(3,9)]: - print(x,y) diff --git a/2017-04-24/itera/iterable2.py b/2017-04-24/itera/iterable2.py deleted file mode 100644 index a948f0b..0000000 --- a/2017-04-24/itera/iterable2.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -list=['kping','sguilian','xiaofei','xiaoxiao'] -for(i=0;i u2: - return 1 - return 0 -print sorted(['bob','about','Zoo','Credit'],cmp_ignore_case) diff --git a/2017-04-24/sorted/reversed_cmp.py b/2017-04-24/sorted/reversed_cmp.py deleted file mode 100644 index 4ba0faf..0000000 --- a/2017-04-24/sorted/reversed_cmp.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def reversed_cmp(x,y): - if x>y: - return -1 - if x < y: - return 1 - return 0 -print sorted([36,5,12,9,21],reversed_cmp) diff --git a/2017-04-24/sorted/sort.py b/2017-04-24/sorted/sort.py deleted file mode 100644 index 4dae62e..0000000 --- a/2017-04-24/sorted/sort.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -print sorted([36,5,12,9,21]) diff --git a/2017-04-24/sorted/strSorted.py b/2017-04-24/sorted/strSorted.py deleted file mode 100644 index 86ca8fa..0000000 --- a/2017-04-24/sorted/strSorted.py +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/env python -print sorted(['bob','about','Zoo','Credit']) diff --git a/2017-04-24p/f_lambda.py b/2017-04-24p/f_lambda.py deleted file mode 100644 index c760915..0000000 --- a/2017-04-24p/f_lambda.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -f=lambda x:x*x -print f -print f(2) diff --git a/2017-04-24p/map_lambda.py b/2017-04-24p/map_lambda.py deleted file mode 100644 index 62b88d0..0000000 --- a/2017-04-24p/map_lambda.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -print map(lambda x:x*x,[1,2,3,4,5,6,7,8,9]) diff --git a/2017-04-25/am/decorator/decorator.py b/2017-04-25/am/decorator/decorator.py deleted file mode 100644 index c4532ca..0000000 --- a/2017-04-25/am/decorator/decorator.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def now(): - print('2017-04-25') -f=now -f() -print now.__name__ -print f.__name__ diff --git a/2017-04-25/am/decorator/decorator_test.py b/2017-04-25/am/decorator/decorator_test.py deleted file mode 100644 index a70983a..0000000 --- a/2017-04-25/am/decorator/decorator_test.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def now(): - print('2017-04-25') -f=now -f() -print now.__name__ -print f.__name__ - -def log(func): - def wrapper(*args,**kw): - print('call %s():' % func.__name__) - return func(*args,**kw) - return wrapper -@log -def now(): - print('2017-04-25') -if __name__=='__main__': - now() diff --git a/2017-04-25/am/decorator/decorator_text.py b/2017-04-25/am/decorator/decorator_text.py deleted file mode 100644 index c8b73de..0000000 --- a/2017-04-25/am/decorator/decorator_text.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def log(text): - def decorator(func): - def wrapper(*args,**kw): - print('%s %s():' % (text, func.__name__)) - return func(*args,**kw) - return wrapper - return decorator -@log('execute') -def now(): - print('2017-04-25') -if __name__=='__main__': - now() diff --git a/2017-04-25/am/filter_1/filter_test.py b/2017-04-25/am/filter_1/filter_test.py deleted file mode 100644 index 41a1b90..0000000 --- a/2017-04-25/am/filter_1/filter_test.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def is_odd(n): - return n % 2 == 1 -if __name__=='__main__': - print filter(is_odd,[1,2,4,5,6,9,10,15]) diff --git a/2017-04-25/am/filter_1/filter_test_empty.py b/2017-04-25/am/filter_1/filter_test_empty.py deleted file mode 100644 index 6f05d04..0000000 --- a/2017-04-25/am/filter_1/filter_test_empty.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def is_odd(n): - return n % 2 == 1 -def not_empty(s): - return s and s.strip() -if __name__=='__main__': - print filter(is_odd,[1,2,4,5,6,9,10,15]) - print filter(not_empty,['A','','B',None,'C',' ']) diff --git a/2017-04-25/am/map_reduce/for_math_function.py b/2017-04-25/am/map_reduce/for_math_function.py deleted file mode 100644 index 8dbeaf5..0000000 --- a/2017-04-25/am/map_reduce/for_math_function.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def f(x): - return x*x -if __name__=='__main__': - L=[] - for n in [1,2,3,4,5,6,7,8,9]: - L.append(f(n)) - print L - - diff --git a/2017-04-25/am/map_reduce/lambda_map_reduce.py b/2017-04-25/am/map_reduce/lambda_map_reduce.py deleted file mode 100644 index 14cdeae..0000000 --- a/2017-04-25/am/map_reduce/lambda_map_reduce.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -def char2num(s): - return{'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s] -def str2int(s): - return reduce(lambda x,y:x*10+y,map(char2num,s)) -if __name__=='__main__': - r=str2int('13579') - print r diff --git a/2017-04-25/am/map_reduce/math_function.py b/2017-04-25/am/map_reduce/math_function.py deleted file mode 100644 index b6887b6..0000000 --- a/2017-04-25/am/map_reduce/math_function.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def f(x): - return x*x -if __name__=='__main__': - result = map(f,[1,2,3,4,5,6,7,8,9]) - print result - diff --git a/2017-04-25/am/map_reduce/numlist_to_charlist.py b/2017-04-25/am/map_reduce/numlist_to_charlist.py deleted file mode 100644 index 490086d..0000000 --- a/2017-04-25/am/map_reduce/numlist_to_charlist.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def num_l_to_char_l(): - r=map(str,[1,2,3,4,5,6,7,8,9]) - print r -if __name__=='__main__': - num_l_to_char_l() diff --git a/2017-04-25/am/map_reduce/reduce_add.py b/2017-04-25/am/map_reduce/reduce_add.py deleted file mode 100644 index 9987777..0000000 --- a/2017-04-25/am/map_reduce/reduce_add.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def add(x,y): - return x + y -if __name__=='__main__': - r=reduce(add,[1,3,5,7,9]) - print r diff --git a/2017-04-25/am/map_reduce/reduce_fn.py b/2017-04-25/am/map_reduce/reduce_fn.py deleted file mode 100644 index b94065a..0000000 --- a/2017-04-25/am/map_reduce/reduce_fn.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def fn(x,y): - return x*10 + y -if __name__=='__main__': - r=reduce(fn,[1,3,5,7,9]) - print r diff --git a/2017-04-25/am/map_reduce/reduce_fn_char2num.py b/2017-04-25/am/map_reduce/reduce_fn_char2num.py deleted file mode 100644 index 3338ea9..0000000 --- a/2017-04-25/am/map_reduce/reduce_fn_char2num.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def fn(x,y): - return x*10 + y -def char2num(s): - return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s] -if __name__=='__main__': - r=reduce(fn,map(char2num,'13579')) - print r diff --git a/2017-04-25/am/map_reduce/reduce_note.txt b/2017-04-25/am/map_reduce/reduce_note.txt deleted file mode 100644 index c8c2b92..0000000 --- a/2017-04-25/am/map_reduce/reduce_note.txt +++ /dev/null @@ -1,3 +0,0 @@ -#再看reduce的用法。 -#reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数,i -#reduce把结果继续和序列的下一个元素做累积计算,其效果就 diff --git a/2017-04-25/am/return_function/close.txt b/2017-04-25/am/return_function/close.txt deleted file mode 100644 index 5bc1fcf..0000000 --- a/2017-04-25/am/return_function/close.txt +++ /dev/null @@ -1 +0,0 @@ -方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变: diff --git a/2017-04-25/am/return_function/close_wait.py b/2017-04-25/am/return_function/close_wait.py deleted file mode 100644 index 8ab4efb..0000000 --- a/2017-04-25/am/return_function/close_wait.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def count(): - def f(j): - def g(): - return j*j - return g - fs=[] - for i in range(1,4): - fs.append(f(i)) - return fs -if __name__=='__main__': - f1,f2,f3=count() - print f1() - print f2() - print f3() - diff --git a/2017-04-25/am/return_function/return_function.py b/2017-04-25/am/return_function/return_function.py deleted file mode 100644 index 59b9cb6..0000000 --- a/2017-04-25/am/return_function/return_function.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def lazy_sum(*args): - def sum(): - ax=0 - for n in args: - ax=ax+n - return ax - return sum -f=lazy_sum(1,3,5,7,9) -print f -print f() - diff --git a/2017-04-25/am/return_function/return_funtions_tired.py b/2017-04-25/am/return_function/return_funtions_tired.py deleted file mode 100644 index 7bfb32d..0000000 --- a/2017-04-25/am/return_function/return_funtions_tired.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def count(): - fs=[] - for i in range(1,4): - def f(): - return i*i - fs.append(f) - return fs -if __name__=='__main__': - f1,f2,f3=count(); - print f1() - print f2() - print f3() - diff --git a/2017-04-25/am/sorted/.reverse_sorted.py.swp b/2017-04-25/am/sorted/.reverse_sorted.py.swp deleted file mode 100644 index c4ee6e5..0000000 Binary files a/2017-04-25/am/sorted/.reverse_sorted.py.swp and /dev/null differ diff --git a/2017-04-25/am/sorted/reverse_sorted.py b/2017-04-25/am/sorted/reverse_sorted.py deleted file mode 100644 index d8fca03..0000000 --- a/2017-04-25/am/sorted/reverse_sorted.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def reversed_cmp(x,y): - if x > y: - return -1 - if x < y: - return 1 - return 0 -if __name__=='__main__': - print sorted([36,21,12,9,21],reversed_cmp) diff --git a/2017-04-25/am/sorted_buildin.py b/2017-04-25/am/sorted_buildin.py deleted file mode 100644 index 4adec9a..0000000 --- a/2017-04-25/am/sorted_buildin.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def sorted_test(): - r=sorted([36,5,12,9,21]) - return r -if __name__=='__main__': - r=sorted_test() - print r diff --git a/2017-04-25/am/variable_function.py b/2017-04-25/am/variable_function.py deleted file mode 100644 index 00135e7..0000000 --- a/2017-04-25/am/variable_function.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- - -def test(): - f=abs - print f(-10) -if __name__=='__main__': - test() - diff --git "a/2017-04-25/am/\351\253\230\351\230\266\345\207\275\346\225\260.txt" "b/2017-04-25/am/\351\253\230\351\230\266\345\207\275\346\225\260.txt" deleted file mode 100644 index 568905f..0000000 --- "a/2017-04-25/am/\351\253\230\351\230\266\345\207\275\346\225\260.txt" +++ /dev/null @@ -1,3 +0,0 @@ -高阶函数英文叫Higher-orger function. 什么是高阶函数, -变量可以指向函数。 - diff --git a/2017-04-25/pm/partial_function/partial.txt b/2017-04-25/pm/partial_function/partial.txt deleted file mode 100644 index fee7487..0000000 --- a/2017-04-25/pm/partial_function/partial.txt +++ /dev/null @@ -1 +0,0 @@ -当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。 diff --git a/2017-04-25/pm/partial_function/partial1.py b/2017-04-25/pm/partial_function/partial1.py deleted file mode 100644 index ab3aa9e..0000000 --- a/2017-04-25/pm/partial_function/partial1.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import functools -if __name__=='__main__': - int2=functools.partial(int,base=2) - print int2('1000000') - print int2('1010101') diff --git a/2017-04-26/instance_attr_and_class_attr/Student.py b/2017-04-26/instance_attr_and_class_attr/Student.py deleted file mode 100644 index ee23354..0000000 --- a/2017-04-26/instance_attr_and_class_attr/Student.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - name='Student' - def __init__(self, name): - self.name=name -if __name__=='__main__': - s=Student('Bob') - s.score=90 - print s.score - print s.name - del s.name - print s.name - #print Student.name diff --git a/2017-04-26/instance_attr_and_class_attr/clss_attr_and_instance_atr.txt b/2017-04-26/instance_attr_and_class_attr/clss_attr_and_instance_atr.txt deleted file mode 100644 index 17d5ad9..0000000 --- a/2017-04-26/instance_attr_and_class_attr/clss_attr_and_instance_atr.txt +++ /dev/null @@ -1,2 +0,0 @@ -#从上面的例子可以看出,在编写程序的时候,千万不要把实例属性和类属性使用相同的名字, -#因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。 diff --git a/2017-04-26/module/hello.py b/2017-04-26/module/hello.py deleted file mode 100644 index 7f49878..0000000 --- a/2017-04-26/module/hello.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -'a hello module' -__author__='kxx' -import sys -def test(): - args=sys.argv - if len(args)==1: - print('Hello,world!') - elif len(args)==2: - print('Hello,%s!' % args[1]) - else: - print('Too many arguments!') -if __name__=='__main__': - test() diff --git a/2017-04-26/module/hello.pyc b/2017-04-26/module/hello.pyc deleted file mode 100644 index 6c452cf..0000000 Binary files a/2017-04-26/module/hello.pyc and /dev/null differ diff --git a/2017-04-26/module/index.html b/2017-04-26/module/index.html deleted file mode 100644 index 13a4089..0000000 --- a/2017-04-26/module/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - sanhai - - -
test
- - diff --git a/2017-04-26/module/module.txt b/2017-04-26/module/module.txt deleted file mode 100644 index 7335793..0000000 --- a/2017-04-26/module/module.txt +++ /dev/null @@ -1,59 +0,0 @@ -,模块 -在计算机程序的开发过程中,随着程序代码越写越多。在一个文件里,代码就会越来越长, -越来越不容易维护。 -为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里。这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个。py文件就称之为一个模块(Module) -使用模块有什么好处? -最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方 -引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。 -使用模块还可以避免函数名和变量名冲突。相同名字的寒舍变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。 -abs() dict() help() min() setattr() -all() dir() hex() next() slice() -any*( divmod() id() object() sorted() -ascii() enumerate() input() oct() staticmethod() -bin() eval() int() open() str() -bool() exec() isinstance() ord() sum() -bytearray() filter() issubclass() powd() super() -bytes() float() iter() print() tuple() -callable() format() len() property() type() -char(). frozenset() list() range() vars() -classmethod() getattrr() locals() repr() zip() -compile() globals() map () reversed() __import__() -complex hasattr max round -deattr hash memoryview set()c78 个内置函数 - -你也许还想到,如果不同的人编写的模块名相同怎么办,为了避免模块冲突,Python -又引入了按目录来组织模块的方法,称为包(Package). -举个例子,一个abc.py的文件就是一个名字叫abc的模块,一个xyz.py的文件就是一个名字叫xyz的模块。 - -现在,假设我们的abc 和xyz这两个模块名字与其他模块冲突了。于是我们可以通过 -包来组织模块, 避免冲突。方法是选择一个顶层包名组织模块,避免冲突。方法选择一个顶层包名, - -请注意,每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany。 - -类似的,可以有多级目录,组成多级层次的包结构。比如如下的目录结构: - -请不用使用python内置的模块命名 -自己创建模块时要注意命名,不能和Python自带的模块名称冲突。例如,系统自带了sys模块,自己的模块就不可命名为sys.py,否则将无法导入系统自带的sys模块。 - -mycompany.web也是一个模块,请指出该模块对应的.py文件。 -P地址,所以,IP地址对应的实际上是计算机的网络接口,通常是网卡。 - - -IP协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块,然后通过IP包发送出去。由于互联网链路复杂,两台计算机之间经常有多条线路,因此,路由器就负责决定如何把一个IP包转发出去。IP包的特点是按块发送,途径多个路由,但不保证能到达,也不保证顺序到达。 - - -P地址实际上是一个32位整数(称为IPv4),以字符串表示的IP地址如192.168.0.1实际上是把32位整数按8位分组后的数字表示,目的是便于阅读。 - -IPv6地址实际上是一个128位整数,它是目前使用的IPv4的升级版,以字符串表示类似于2001:0db8:85a3:0042:1000:8a2e:0370:7334。 - -TCP协议则是建立在IP协议之上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。 - -许多常用的更高级的协议都是建立在TCP协议基础上的,比如用于浏览器的HTTP协议、发送邮件的SMTP协议等。 - -一个IP包除了包含要传输的数据外,还包含源IP地址和目标IP地址,源端口和目标端口。 - -端口有什么作用?在两台计算机通信时,只发IP地址是不够的,因为同一台计算机上跑着多个网络程序。一个IP包来了之后,到底是交给浏览器还是QQ,就需要端口号来区分。每个网络程序都向操作系统申请唯一的端口号,这样,两个进程在两台计算机之间建立网络连接就需要各自的IP地址和各自的端口号。 - -一个进程也可能同时与多个计算机建立链接,因此它会申请很多端口。 - -了解了TCP/IP协议的基本概念,IP地址和端口的概念,我们就可以开始进行网络编程了。 diff --git a/2017-04-26/module/path.txt b/2017-04-26/module/path.txt deleted file mode 100644 index be2386c..0000000 --- a/2017-04-26/module/path.txt +++ /dev/null @@ -1 +0,0 @@ -/root/python1/python_execise/2017-04-26/module diff --git a/2017-04-26/module/testb4.py b/2017-04-26/module/testb4.py deleted file mode 100644 index 33575d3..0000000 --- a/2017-04-26/module/testb4.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -from bs4 import BeautifulSoup -soup = BeautifulSoup(open('index.html'),"html5lib") -soup = BeautifulSoup("data","html5lib") diff --git a/2017-04-26/module/using_module.txt b/2017-04-26/module/using_module.txt deleted file mode 100644 index f15e391..0000000 --- a/2017-04-26/module/using_module.txt +++ /dev/null @@ -1,7 +0,0 @@ -使用模块 -Python本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用。 -我们以内建的sys模块为例 - -Python的内置的函数和模块。 -也要第三方的模块。模块就是由好多函数组成。 - diff --git a/2017-04-26/oop/Student.py b/2017-04-26/oop/Student.py deleted file mode 100644 index 6f58403..0000000 --- a/2017-04-26/oop/Student.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name,score): - self.name=name - self.score=score - def print_score(self): - print('%s: %s' % (self.name,self.score)) -if __name__=='__main__': - bart=Student('Bart Simpson',59) - lisa=Student('Lisa Simpson',87) - bart.print_score() - lisa.print_score() diff --git a/2017-04-26/oop/Student2.py b/2017-04-26/oop/Student2.py deleted file mode 100644 index ad4d271..0000000 --- a/2017-04-26/oop/Student2.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/env python -clas Student(object): - pass diff --git a/2017-04-26/oop/Student3.py b/2017-04-26/oop/Student3.py deleted file mode 100644 index 88b9e84..0000000 --- a/2017-04-26/oop/Student3.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- codinig:utf-8 -*- -class Student(object): - pass -if __name__=='__main__': - bart=Student() - print bart - print Student diff --git a/2017-04-26/oop/Student_Bind.py b/2017-04-26/oop/Student_Bind.py deleted file mode 100644 index 18e3703..0000000 --- a/2017-04-26/oop/Student_Bind.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- codinig:utf-8 -*- -class Student(object): - pass -if __name__=='__main__': - bart=Student() - bart.name='Bart Simpson' - print bart.name - #print bart - #print Student diff --git a/2017-04-26/oop/Student_Class/Student.py b/2017-04-26/oop/Student_Class/Student.py deleted file mode 100644 index 2b63655..0000000 --- a/2017-04-26/oop/Student_Class/Student.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name,score): - self.name=name - self.score=score -if __name__=='__main__': - bart=Student('Bart Simpson',59) - print bart - print bart.name diff --git a/2017-04-26/oop/access_limit/Student.py b/2017-04-26/oop/access_limit/Student.py deleted file mode 100644 index f7789f5..0000000 --- a/2017-04-26/oop/access_limit/Student.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name,score): - self.__name=name - self.__score=score - def print_score(self): - print('%s: %s' % (self.__name,self.__score)) - def get_name(self): - return self.__name - def get_score(self): - return self.__score - def set_score(self,score): - if 0 <= score <= 100: - self.__score=score - else: - raise ValueError('bad score') - -if __name__=='__main__': - bart=Student('Bart Simpson',98) - print bart.__name diff --git a/2017-04-26/oop/encapsulation/Student.py b/2017-04-26/oop/encapsulation/Student.py deleted file mode 100644 index 7a7c3a5..0000000 --- a/2017-04-26/oop/encapsulation/Student.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name,score): - self.name=name - self.score=score - def print_score(self): - print('%s: %s' % (self.name, self.score)) - def get_grade(self): - if self.score >=90: - return 'A' - elif self.score >= 60: - return 'B' - else: - return 'C' -if __name__=='__main__': - bart=Student('张琰',120) - a=bart.get_grade() - print a - - diff --git a/2017-04-26/oop/ensuplation/Student.py b/2017-04-26/oop/ensuplation/Student.py deleted file mode 100644 index 2f9214a..0000000 --- a/2017-04-26/oop/ensuplation/Student.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name,score): - self.name=name - self.score=score - def print_score(self): - print('%s:%s' % (self.name,self.score)) -if __name__=='__main__': - bart=Student('zy','100') - bart.print_score() diff --git a/2017-04-26/oop/extend/Animal.py b/2017-04-26/oop/extend/Animal.py deleted file mode 100644 index 9d7384c..0000000 --- a/2017-04-26/oop/extend/Animal.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Animal(object): - def run(self): - print('Animal is running...') -class Dog(Animal): - def run(self): - print('Dog is running...') - def eat(self): - print('Eating meat...') -class Cat(Animal): - def run(self): - print('Cat is running...') -if __name__=='__main__': - dog=Dog() - dog.run() - cat=Cat() - cat.run() diff --git a/2017-04-26/oop/process_inter.py b/2017-04-26/oop/process_inter.py deleted file mode 100644 index cfd5bbd..0000000 --- a/2017-04-26/oop/process_inter.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from multiprocessing import Process,Queue -import os,time,random -#写数据进程执行的代码 -def write(q): - print('Process to write:%s' % os.getpid()) - for value in ['A','B','C']: - print('Put %s to queue...' % value) - q.put(value) - time.sleep(random.random()) -#读数据进程执行的代码: -def read(q): - print('Process to read:%s' % os.getpid()) - while True: - value = q.get(True) - print('Get %s from queue.' % value) -if __name__=='__main__': - #父进程创建Quue.并传给各个子进程. - q = Queue() - pw = Process(target=write,args=(q,)) - pr = Process(target=read, args=(q,)) - #启动子进程pw, 写入. - pw.start() - #启动子进程pr.读取 - pr.start() - #等待pw结束 - pw.join() - #pr进程里是死循环,无法等待其结束,只能强行终止 - pr.terminate() diff --git a/2017-04-26/oop/thread.txt b/2017-04-26/oop/thread.txt deleted file mode 100644 index f59de2c..0000000 --- a/2017-04-26/oop/thread.txt +++ /dev/null @@ -1 +0,0 @@ -,它需要先保存当前执行的现场环境(CPU寄存器状态、内存页等),然后,把新任务的执行环境准备好(恢复上次的寄存器状态,切换内存页等),才能开始执行。这个切换过程虽然很快,但是也需要耗费时间。如果有几千个任务同时进行,操作系统可能就主要忙着切换任务,根本没有多少时间去执行任务了,这种情况最常见的就是硬盘狂响,点窗口无反应,系统处于假死状态。 diff --git a/2017-04-26/oop/type_object/pyshell_hist.txt b/2017-04-26/oop/type_object/pyshell_hist.txt deleted file mode 100644 index 5437580..0000000 --- a/2017-04-26/oop/type_object/pyshell_hist.txt +++ /dev/null @@ -1,55 +0,0 @@ - -pyright", "credits" or "license" for more information. ->>> a='1' ->>> type(a) - ->>> a=1 ->>> type(a) - ->>> a=[] ->>> type(a) - ->>> a={} ->>> type(a) - ->>> a=[] ->>> type(a) - ->>> a=() ->>> type(a) - ->>> a=True ->>> type(a) - ->>> a=1.2 ->>> type(a) - ->>> a=u'1' ->>> type(a) - ->>> type(12)==type(456) -True ->>> type(123)=int - File "", line 1 -SyntaxError: can't assign to function call ->>> type(123)==int -True ->>> type('123')==type('123') -True ->>> type('abc')==str -True ->>> type('abc')==type(123) -False ->>> import types ->>> def fn(): -... pass -... ->>> type(fn)==types.FunctionType -True ->>> type(abs)==types.BuiltinFunctionType -True ->>> type(lambda x:x)==types.LambdaType -True ->>> type((x for x in range(10)))==types.GeneratorType -True ->>> diff --git a/2017-04-26/oop/using_dir/getattr.txt b/2017-04-26/oop/using_dir/getattr.txt deleted file mode 100644 index 95d6174..0000000 --- a/2017-04-26/oop/using_dir/getattr.txt +++ /dev/null @@ -1,41 +0,0 @@ -紧接着,可以测试该对象的属性: - ->>> hasattr(obj, 'x') # 有属性'x'吗? -True ->>> obj.x -9 ->>> hasattr(obj, 'y') # 有属性'y'吗? -False ->>> setattr(obj, 'y', 19) # 设置一个属性'y' ->>> hasattr(obj, 'y') # 有属性'y'吗? -True ->>> getattr(obj, 'y') # 获取属性'y' -19 ->>> obj.y # 获取属性'y' -19 -如果试图获取不存在的属性,会抛出AttributeError的错误: - ->>> getattr(obj, 'z') # 获取属性'z' -Traceback (most recent call last): - File "", line 1, in -AttributeError: 'MyObject' object has no attribute 'z' -可以传入一个default参数,如果属性不存在,就返回默认值: - ->>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404 -404 -也可以获得对象的方法: - ->>> hasattr(obj, 'power') # 有属性'power'吗? -True ->>> getattr(obj, 'power') # 获取属性'power' -> ->>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn ->>> fn # fn指向obj.power -> ->>> fn() # 调用fn()与调用obj.power()是一样的 -81 -小结 - -通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息。如果可以直接写: - -sum = obj.x + obj.y diff --git a/2017-04-26/oop/using_dir/py_shell_hist.txt b/2017-04-26/oop/using_dir/py_shell_hist.txt deleted file mode 100644 index 6d44f52..0000000 --- a/2017-04-26/oop/using_dir/py_shell_hist.txt +++ /dev/null @@ -1,3 +0,0 @@ ->> dir('12') -['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] ->>> diff --git a/2017-04-26/oop/using_dir/using_dir.txt b/2017-04-26/oop/using_dir/using_dir.txt deleted file mode 100644 index 5bf15b1..0000000 --- a/2017-04-26/oop/using_dir/using_dir.txt +++ /dev/null @@ -1,6 +0,0 @@ -使用dir() -相对了man -如果相获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list. -比如,获得一个str对象的所有属性后方法。 - -类似__xxx__的属性和方法在Python中都是有特殊用途的,比如__len__方法返回长度。在Python中,如果你调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的__len__()方法,所以,下面的代码是等价的: diff --git "a/2017-04-26/oop/\350\216\267\345\217\226\345\257\271\350\261\241\344\277\241\346\201\257.txt" "b/2017-04-26/oop/\350\216\267\345\217\226\345\257\271\350\261\241\344\277\241\346\201\257.txt" deleted file mode 100644 index b377b87..0000000 --- "a/2017-04-26/oop/\350\216\267\345\217\226\345\257\271\350\261\241\344\277\241\346\201\257.txt" +++ /dev/null @@ -1,5 +0,0 @@ -获取对象信息 -当我们拿到一个对象的引用时,如何知道这个对象是什么类型,有哪些方法呢? -使用type() -首先,我们来判断对象类型,使用type()函数: -基本类型都可以用type()判断 diff --git a/2017-04-26/oop_advance/customed_class/Student.py b/2017-04-26/oop_advance/customed_class/Student.py deleted file mode 100644 index 900545e..0000000 --- a/2017-04-26/oop_advance/customed_class/Student.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name): - self.name=name - def __call__(self): - print('My name is %s.' % self.name) -if __name__=='__main__': - s=Student('Michael'); - s() diff --git a/2017-04-26/oop_advance/customed_class/callable.txt b/2017-04-26/oop_advance/customed_class/callable.txt deleted file mode 100644 index ad3a6dd..0000000 --- a/2017-04-26/oop_advance/customed_class/callable.txt +++ /dev/null @@ -1,7 +0,0 @@ -过callable()函数,我们就可以判断一个对象是否是“可调用”对象。 - -小结 - -Python的class允许定义许多定制方法,可以让我们非常方便地生成特定的类。 - -本节介绍的是最常用的几个定制方法,还有很多可定制的方法, diff --git a/2017-04-26/oop_advance/enum/enum_class.py b/2017-04-26/oop_advance/enum/enum_class.py deleted file mode 100644 index b9ffd6c..0000000 --- a/2017-04-26/oop_advance/enum/enum_class.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from enum import Enum -if __name__=='__main__': - Month=Enum('Month',('Jan','Feb','Mar','Apr','May','Jun','Aug','Sep','Oct','Nov','Dec')) - for name,member in Month.__members__.items(): - print(name,'=>',member,',',member.value) - diff --git a/2017-04-26/oop_advance/enum/enum_class_value.py b/2017-04-26/oop_advance/enum/enum_class_value.py deleted file mode 100644 index 80ecc8b..0000000 --- a/2017-04-26/oop_advance/enum/enum_class_value.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from enum import Enum,unique -@unique -class Weekday(Enum): - Sun=0 - Mon=1 - Tue=2 - Wed=3 - Thu=4 - Fri=5 - Sat=6 -if __name__=='__main__': - for name, member in Weekday.__members__.items(): - print(name, '=>', member) diff --git a/2017-04-26/oop_advance/multi_process/bind-util.txt b/2017-04-26/oop_advance/multi_process/bind-util.txt deleted file mode 100644 index 3ec607e..0000000 --- a/2017-04-26/oop_advance/multi_process/bind-util.txt +++ /dev/null @@ -1 +0,0 @@ -yum provides */nslookup diff --git a/2017-04-26/oop_advance/multi_process/fork.txt b/2017-04-26/oop_advance/multi_process/fork.txt deleted file mode 100644 index bb03933..0000000 --- a/2017-04-26/oop_advance/multi_process/fork.txt +++ /dev/null @@ -1,2 +0,0 @@ -见的Apache服务器就是由父进程监听端口,每当有新的http请求时,就fork出子进程来处理新的http请求。 - diff --git a/2017-04-26/oop_advance/multi_process/multi_process.txt b/2017-04-26/oop_advance/multi_process/multi_process.txt deleted file mode 100644 index 8e95a10..0000000 --- a/2017-04-26/oop_advance/multi_process/multi_process.txt +++ /dev/null @@ -1,8 +0,0 @@ -要上python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识。 - -Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊,普通的函数调用, 调用一次,返回一次,但是fork()调用一次,返回两次, -因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。 - -子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。 - -Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程: diff --git a/2017-04-26/oop_advance/multi_process/multiprocessing.txt b/2017-04-26/oop_advance/multi_process/multiprocessing.txt deleted file mode 100644 index 8734f00..0000000 --- a/2017-04-26/oop_advance/multi_process/multiprocessing.txt +++ /dev/null @@ -1,7 +0,0 @@ -如果你打算写多进程的服务程序,Unix/Linux无疑是正常的选择。由于Windows没有fork调用。 -难道在Windwos上无法用Python编写多进程的程序。 - -由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。 -multiprocessing模块提供了一个Process类来代表一个进程对象。 -下面的例子演示了启动一个子进程并等待其结束. - diff --git a/2017-04-26/oop_advance/multi_process/multiprocessing_cod.py b/2017-04-26/oop_advance/multi_process/multiprocessing_cod.py deleted file mode 100644 index 3802e63..0000000 --- a/2017-04-26/oop_advance/multi_process/multiprocessing_cod.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from multiprocessing import Process -import os -def run_proc(name): - print('Run child process %s (%s)...' % (name, os.getpid())) -if __name__=='__main__': - print('Parent process %s.' % os.getpid()) - p=Process(target=run_proc,args=('test',)) - print('Child process will start.') - p.start() - p.join() - print('Child process end.') diff --git a/2017-04-26/oop_advance/multi_process/muti1.py b/2017-04-26/oop_advance/multi_process/muti1.py deleted file mode 100644 index b1ecfb6..0000000 --- a/2017-04-26/oop_advance/multi_process/muti1.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from multiprocessing import Pool -import os,time,random -def long_time_task(name): - print('Run task %s (%s)...' % (name,os.getpid())) - start = time.time() - time.sleep(random.random()*3) - ebd = time.time() - print('Task %s runs %0.2f seconds.' % (name,(end - start))) -if __name__=='__main__': - print('Parent process %s.' % os.getpid()) - p=Pool(4) - for i in range(5): - p.apply_async(long_time_task,args=(i,)) - print('Waiting for all subprocesses done...') - p.close() - p.join() - print('All subprocesses done.') diff --git a/2017-04-26/oop_advance/multi_process/os_fork.py b/2017-04-26/oop_advance/multi_process/os_fork.py deleted file mode 100644 index 970d813..0000000 --- a/2017-04-26/oop_advance/multi_process/os_fork.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import os -print('Process (%s) start...' % os.getpid()) -#Only works on Unix/Linux/Mac -pid = os.fork() -if pid == 0: - print('I am child process (%s) and my prarent is %s.' % (os.getpid(), os.getppid())) -else: - print('I (%s) just created a child process (%s).' % (os.getpid(),pid)) diff --git a/2017-04-26/oop_advance/multi_process/subprocess_tst.py b/2017-04-26/oop_advance/multi_process/subprocess_tst.py deleted file mode 100644 index 263d34f..0000000 --- a/2017-04-26/oop_advance/multi_process/subprocess_tst.py +++ /dev/null @@ -1,5 +0,0 @@ -import subprocess - -print('$ nslookup www.python.org') -r = subprocess.call(['nslookup', 'www.python.org']) -print('Exit code:', r) diff --git a/2017-04-26/oop_advance/oop_advance.txt b/2017-04-26/oop_advance/oop_advance.txt deleted file mode 100644 index 2a7b6be..0000000 --- a/2017-04-26/oop_advance/oop_advance.txt +++ /dev/null @@ -1,9 +0,0 @@ -面向对象高级编程 - -数据封装, 继承和多态只是面向对象程序设计中最基础的3个概念,在PYthon中,面向对象还有很多高级特性,允许我们写出非常强大的功能。 -我们会讨论多重继承,定制类,元类等概念。 -使用—__slots__ -正常情况下,当我们定义一个class,创建一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。先定义class -class Student(object): - pass - diff --git a/2017-04-26/oop_advance/slots_function.py b/2017-04-26/oop_advance/slots_function.py deleted file mode 100644 index 19b4731..0000000 --- a/2017-04-26/oop_advance/slots_function.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/env python -# -*- coding"utf-8 -*- -class Student(object): - pass -def set_age(self,age): - self.age=age -from types import MethodType -if __name__=='__main__': - s=Student() - s.name='Michael' - print s.name -# s.set_age=MethodType(set_age,s) - Student.set_age=set_age - s.set_age(25) - print s.age - s2=Student() - s2.set_age(25) diff --git a/2017-04-26/oop_advance/slots_using.py b/2017-04-26/oop_advance/slots_using.py deleted file mode 100644 index 61b9fb6..0000000 --- a/2017-04-26/oop_advance/slots_using.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - pass -if __name__=='__main__': - s=Student - s.name='Mike' - print(s.name) diff --git a/2017-04-26/oop_advance/slots_using2.py b/2017-04-26/oop_advance/slots_using2.py deleted file mode 100644 index bba5fe7..0000000 --- a/2017-04-26/oop_advance/slots_using2.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - __slots__=('name','age') -class GraduateStudent(Student): - pass -if __name__=='__main__': - s=Student() - s.name='Michael' - s.age=25 - g=GraduateStudent() - g.score=99 - print g.score diff --git a/2017-04-26/oop_advance/using@property/Student.py b/2017-04-26/oop_advance/using@property/Student.py deleted file mode 100644 index c4ca370..0000000 --- a/2017-04-26/oop_advance/using@property/Student.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/env python -class Student(object): - @property - def score(self): - return self._score - @score.setter - def score(self,value): - if not isinstance(value, int): - raise ValueError('score must be an integer!') - if value < 0 or value > 100: - raise ValueError('score must between 0~100!') - self._score=value -if __name__=='__main__': - s=Student() - s.score=60 - print s.score diff --git a/2017-04-26/oop_advance/using@property/Teacher.py b/2017-04-26/oop_advance/using@property/Teacher.py deleted file mode 100644 index be61090..0000000 --- a/2017-04-26/oop_advance/using@property/Teacher.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name): - self.name=name - def __str__(self): - return 'Student object (name:%s)' % self.name - __repr__=__str__ -if __name__=='__main__': - def __init__(self,name): - self.name=name - def __str__(self): - return 'Student object(name:%s)' % self.name - print Student('Michael') diff --git a/2017-04-26/oop_advance/using@property/customed_class.txt b/2017-04-26/oop_advance/using@property/customed_class.txt deleted file mode 100644 index 8512293..0000000 --- a/2017-04-26/oop_advance/using@property/customed_class.txt +++ /dev/null @@ -1,2 +0,0 @@ -__str__ 相对于java的toString方法 - diff --git a/2017-04-27/at_propertiy/Student.py b/2017-04-27/at_propertiy/Student.py deleted file mode 100644 index 765352b..0000000 --- a/2017-04-27/at_propertiy/Student.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - @property - def score(self): - return self._score - @score.setter - def score(self,value): - if not isinstance(value,int): - raise ValueError('score must be an integer!') - if value < 0 or value > 100: - raise ValueError('score must between 0 ~ 100!') - self._score = value -if __name__=='__main__': - s=Student() - s.score=60 - print s.score diff --git a/2017-04-27/at_propertiy/at_property.txt b/2017-04-27/at_propertiy/at_property.txt deleted file mode 100644 index c70dfc2..0000000 --- a/2017-04-27/at_propertiy/at_property.txt +++ /dev/null @@ -1,19 +0,0 @@ -在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数, - 导致可以把成绩随便改。 - -s = Student() -s.score = 9999 -这显然不合逻辑,为了限制score的范围, - 可以通过一个set_score()方法来设置成绩。 -再通过一个get_score()来获取成绩,这样 -在set_score()方法里, 就可以检查参数。 -class Student(object): - def get_score(self): - return self._score - def set_score(self, value): - if not isinstance(value, int): - raise ValueError("score must be an integer!") - if value < 0 or value > 100: - railse ValueError('score must be an integer!') - self._score=value - diff --git a/2017-04-27/call_instance/Student.py b/2017-04-27/call_instance/Student.py deleted file mode 100644 index 116ae20..0000000 --- a/2017-04-27/call_instance/Student.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -# 测试中文 -#把函数看成对象,因为这两者之间本来就没啥根本的区别。 -class Student(object): - def __init__(self, name): - self.name = name - def __call__(self): - print('My name is %s.' % self.name) -if __name__=='__main__': - s=Student('Michael') - s() - print callable(Student('test')) - print callable(max) - print callable([1,2,3]) - print callable(None) - print callable('str') diff --git a/2017-04-27/customed_class/Fib.py b/2017-04-27/customed_class/Fib.py deleted file mode 100644 index 4a48d94..0000000 --- a/2017-04-27/customed_class/Fib.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/env python -class Fib(object): - def __getitem__(self,n): - if isinstance(n,int): - a,b=1,1 - for x in range(n): - a,b = b, a + b - return a - if isinstance(n,slice): - start = n.start - stop = n.stop - if start is None: - start = 0 - a,b=1,1 - L = [] - for x in range(stop): - if x >= start: - L.append(a) - a,b=b,a+b - return L -if __name__=='__main__': - f = Fib() - print f[0:5] - print f[:10] diff --git a/2017-04-27/customed_class/Student.py b/2017-04-27/customed_class/Student.py deleted file mode 100644 index c24f7b2..0000000 --- a/2017-04-27/customed_class/Student.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self, name): - self.name = name - def __str__(self): - return 'Student object (name : %s)' % self.name - __repr__ = __str__ -if __name__=='__main__': - s=Student('Nike') - print s diff --git a/2017-04-27/enum_class/Enum2.py b/2017-04-27/enum_class/Enum2.py deleted file mode 100644 index 31af6ef..0000000 --- a/2017-04-27/enum_class/Enum2.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -#@unique装饰器可以帮助我们检查保证没有重复值。 -#Enum可以把一组相关常量定义在一个class中,且class不可变,而且成员可以直接比较。 -from enum import Enum,unique -@unique -class Weekday(Enum): - Sun=0 - Mon=1 - Tue=2 - Wed=3 - Thu=4 - Fri=5 - Sat=6 -if __name__=='__main__': - day1=Weekday.Mon - print day1 - print Weekday['Tue'] - print Weekday.Tue.value - print(day1 == Weekday.Mon) diff --git a/2017-04-27/enum_class/Month.py b/2017-04-27/enum_class/Month.py deleted file mode 100644 index 2452acd..0000000 --- a/2017-04-27/enum_class/Month.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from enum import Enum -Month=Enum('Month',('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')) -for name,member in Month.__members__.items(): - print(name, '=>', member, ',', member.value) diff --git a/2017-04-27/get_attr/Student.py b/2017-04-27/get_attr/Student.py deleted file mode 100644 index 6146979..0000000 --- a/2017-04-27/get_attr/Student.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self): - self.name = 'Michael' -#动态返回属性 - def __getattr__(self, attr): - if attr=='score': - return 99 - if attr=='age': - return lambda:25 -if __name__=='__main__': - s = Student() - print s.name - print s.score - print s.age() diff --git a/2017-04-27/meta_class/meta.txt b/2017-04-27/meta_class/meta.txt deleted file mode 100644 index 56440c8..0000000 --- a/2017-04-27/meta_class/meta.txt +++ /dev/null @@ -1,34 +0,0 @@ -要创建一个class对象,type()函数依次传入3个参数: - -class的名称; -继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法; -class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。 - -metaclass - -了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass。 - -metaclass,直译为元类,简单的解释就是: - -当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。 - -但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。 - -连接起来就是:先定义metaclass,就可以创建类,最后创建实例。 - -所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。 - -metaclass是Python面向对象里最难理解,也是最难使用的魔术代码。正常情况下,你不会碰到需要使用metaclass的情况,所以,以下内容看不懂也没关系,因为基本上你不会用到。 - -我们先看一个简单的例子,这个metaclass可以给我们自定义的MyList增加一个add方法: -当我们传入关键字参数metaclass时,魔术就生效了,它指示Python解释器在创建MyList时,要通过ListMetaclass.__new__()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。 - -__new__()方法接收到的参数依次是: - -当前准备创建的类的对象; - -类的名字; - -类继承的父类集合; - -类的方法集合。 diff --git a/2017-04-27/oop/MyClass.py b/2017-04-27/oop/MyClass.py deleted file mode 100644 index dadc32f..0000000 --- a/2017-04-27/oop/MyClass.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class MyClass(): - x=100 - def func(self,name): - return "Hi %s!" % name - def func2(self): - return self.x -if __name__=='__main__': - mc = MyClass() - print mc.x - print mc.func('xiaoqiang') - print mc.func2() - diff --git a/2017-04-27/oop/oop.txt b/2017-04-27/oop/oop.txt deleted file mode 100644 index 33423ef..0000000 --- a/2017-04-27/oop/oop.txt +++ /dev/null @@ -1,19 +0,0 @@ -__init__(self,...) 初始化对象,在创建新对象时调用。 -__del__(self) 释放对象, 在对象被删除之前调用。 - -__new__(cls,*args,**kwd) - 实例的生成操作,在__init__(self)之前调用 -__str__(self) 在使用print 语句时被调用,返回一个字符串。 -__getitem__(self,key) 获取序列的索引key对应的值,等价于seq[key] -__len__(self) 在调用内建函数len()时被调用。 -__cmp__(str,dst) 比较两个对象src和dst -__getattr__(s,name) 获取属性的值 -__setattr__(s,name,value) 设置属性的值 -__delattr__(s,name) 删除属性 -__gt__(self,other) 判断self对象是否大于other对象。 -__lt__(self,other)判断self对象是否小于other对象 -__ge__(self, other) 判断 self 对象是否大于或等于 other 对象 -__le__(self, other) 判断 self 对象是否小于或等于 other 对象 -__eq__(self, other) 判断 self 对象是否等于 other 对象 -__call__(self, *args) 把实例对象作为函数调用 - diff --git a/2017-04-27/oop/url2.py b/2017-04-27/oop/url2.py deleted file mode 100644 index 7f33338..0000000 --- a/2017-04-27/oop/url2.py +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/env python3 -# -*- coding:utf-8 -*- -from urllib import request -#这是python3的模块 如果有错误,请使用python3运行 -with request.urlopen('https://api.douban.com/v2/book/2129650') as f: - data = f.read() - print('Status:', f.status, f.reason) - for k, v in f.getheaders(): - print('%s: %s' % (k, v)) - print('Data:', data.decode('utf-8')) diff --git a/2017-04-27/property_read/MultExtend.py b/2017-04-27/property_read/MultExtend.py deleted file mode 100644 index dfbb1f7..0000000 --- a/2017-04-27/property_read/MultExtend.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Runnable(object): - def run(self): - print('Running...') -class Flyable(object): - def fly(self): - print('Running...') -class Animal(object): - pass -class Mannal(Animal): - pass -class Bird(Animal): - pass -class Dog(Mammal, Runnable): - pass -class Bat(Mammali,Flyable): - pass -class Parrot(Bird): - pass -class Ostrich(Bird): diff --git a/2017-04-27/property_read/Student.py b/2017-04-27/property_read/Student.py deleted file mode 100644 index b0ec16d..0000000 --- a/2017-04-27/property_read/Student.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - @property - def birth(self): - return self._birth - @birth.setter - def birth(self,value): - self._birth = value - - @property - def age(self): - return 2017 -self._birth -if __name__=='__main__': - s=Student(); - s.birth=1989 - print s.age - s.age=11 diff --git a/2017-04-27/property_read/property.txt b/2017-04-27/property_read/property.txt deleted file mode 100644 index a1f8f28..0000000 --- a/2017-04-27/property_read/property.txt +++ /dev/null @@ -1,3 +0,0 @@ -@property可以读 -@字段名 .setter可以写。 -光有@property是只读属性。 diff --git "a/2017-04-27/property_read/\345\257\271\351\207\215\347\273\247\346\211\277.txt" "b/2017-04-27/property_read/\345\257\271\351\207\215\347\273\247\346\211\277.txt" deleted file mode 100644 index ca3f3aa..0000000 --- "a/2017-04-27/property_read/\345\257\271\351\207\215\347\273\247\346\211\277.txt" +++ /dev/null @@ -1,18 +0,0 @@ -继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功能。 -Dog Bat Parrot Ostrich - Animal -Mammal Bird -Dog Bat Parrot Ostrich - -Animal -Runnable Flyable - -Dog Ostrich Parrot Bat - - Animal -Mammal BirD - -MRun MFly BRun BFly - -Dog Bat Ostrich Parrot - diff --git a/2017-04-27/slot/.Student.py.swp b/2017-04-27/slot/.Student.py.swp deleted file mode 100644 index 7bc87b4..0000000 Binary files a/2017-04-27/slot/.Student.py.swp and /dev/null differ diff --git a/2017-04-28/doctest/doc.py b/2017-04-28/doctest/doc.py deleted file mode 100644 index b704286..0000000 --- a/2017-04-28/doctest/doc.py +++ /dev/null @@ -1,38 +0,0 @@ -class Dict(dict): - ''' - Simple dict but also support access as x.y style. - - >>> d1 = Dict() - >>> d1['x'] = 100 - >>> d1.x - 100 - >>> d1.y = 200 - >>> d1['y'] - 200 - >>> d2 = Dict(a=1, b=2, c='3') - >>> d2.c - '3' - >>> d2['empty'] - Traceback (most recent call last): - ... - KeyError: 'empty' - >>> d2.empty - Traceback (most recent call last): - ... - AttributeError: 'Dict' object has no attribute 'empty' - ''' - def __init__(self, **kw): - super(Dict, self).__init__(**kw) - - def __getattr__(self, key): - try: - return self[key] - except KeyError: - raise AttributeError(r"'Dict' object has no attribute '%s'" % key) - - def __setattr__(self, key, value): - self[key] = value - -if __name__=='__main__': - import doctest - doctest.testmod() diff --git a/2017-04-28/error_debug/debugging.txt b/2017-04-28/error_debug/debugging.txt deleted file mode 100644 index 2a73f32..0000000 --- a/2017-04-28/error_debug/debugging.txt +++ /dev/null @@ -1,67 +0,0 @@ - -n的调试器pdb,让程序以单步方式运行,可以随时查看运行状态。我们先准备好程序: - -# err.py -s = '0' -n = int(s) -print 10 / n -然后启动: - -$ python -m pdb err.py -> /Users/michael/Github/sicp/err.py(2)() --> s = '0' -以参数-m pdb启动后,pdb定位到下一步要执行的代码-> s = '0'。输入命令l来查看代码: - -(Pdb) l - 1 # err.py - 2 -> s = '0' - 3 n = int(s) - 4 print 10 / n -[EOF] -输入命令n可以单步执行代码: - -(Pdb) n -> /Users/michael/Github/sicp/err.py(3)() --> n = int(s) -(Pdb) n -> /Users/michael/Github/sicp/err.py(4)() --> print 10 / n -任何时候都可以输入命令p 变量名来查看变量: - -(Pdb) p s -'0' -(Pdb) p n -0 -输入命令q结束调试,退出程序: - -(Pdb) n -ZeroDivisionError: 'integer division or modulo by zero' -> /Users/michael/Github/sicp/err.py(4)() --> print 10 / n -(Pdb) q -这种通过pdb在命令行调试的方法理论上是万能的,但实在是太麻烦了,如果有一千行代码,要运行到第999行得敲多少命令啊。还好,我们还有另一种调试方法。 - -pdb.set_trace() - -这个方法也是用pdb,但是不需要单步执行,我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点: - -# err.py -import pdb - -s = '0' -n = int(s) -pdb.set_trace() # 运行到这里会自动暂停 -print 10 / n -运行代码,程序会自动在pdb.set_trace()暂停并进入pdb调试环境,可以用命令p查看变量,或者用命令c继续运行: - -$ python err.py -> /Users/michael/Github/sicp/err.py(7)() --> print 10 / n -(Pdb) p n -0 -(Pdb) c -Traceback (most recent call last): - File "err.py", line 7, in - print 10 / n -ZeroDivisionError: integer division or modulo by zero -这个方式比直接启动pdb单步调试效率要高很多,但也高不到哪去。 diff --git a/2017-04-28/error_debug/error.py b/2017-04-28/error_debug/error.py deleted file mode 100644 index 098c9d1..0000000 --- a/2017-04-28/error_debug/error.py +++ /dev/null @@ -1,7 +0,0 @@ -# err.py -import logging -logging.basicConfig(level=logging.INFO) -s = '0' -n = int(s) -logging.info('n = %d' % n) -print 10 / n diff --git a/2017-04-28/error_debug/logging.txt b/2017-04-28/error_debug/logging.txt deleted file mode 100644 index 6df17e0..0000000 --- a/2017-04-28/error_debug/logging.txt +++ /dev/null @@ -1,3 +0,0 @@ -写程序最痛苦的事情莫过于调试,程序往往会以你意想不到的流程来运行,你期待执行的语句其实根本没有执行,这时候,就需要调试了。 - -虽然用IDE调试起来比较方便,但是最后你会发现,logging才是终极武器。 diff --git a/2017-04-28/exception_kind/err.py b/2017-04-28/exception_kind/err.py deleted file mode 100644 index 45ba875..0000000 --- a/2017-04-28/exception_kind/err.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -def foo(s): - n = int(s) - return 10 / n -def bar(s): - try: - return foo(s)*2 - except StandardError,e: - print 'Error!' - raise - - -def main(): - bar('0') - - -main() diff --git a/2017-04-28/exception_kind/exception.py b/2017-04-28/exception_kind/exception.py deleted file mode 100644 index cf99c0b..0000000 --- a/2017-04-28/exception_kind/exception.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -if __name__=='__main__': - - try: - print 'try...' - r = 10 /0 - print 'result:',r - except ZeroDivisionError,e: - print 'except:',e - print 'hello' - finally: - print 'finally...' - print 'END' - - diff --git a/2017-04-28/exception_kind/python_exception.txt b/2017-04-28/exception_kind/python_exception.txt deleted file mode 100644 index 99bdc23..0000000 --- a/2017-04-28/exception_kind/python_exception.txt +++ /dev/null @@ -1,12 +0,0 @@ -在程序运行过程中,总会遇到各种各样的错误。 -有的错误是程序编写有问题造成的,比如本来应该输出整数结果 - -输出了字符串, 这种错误我们通常称之为bug, bug是必须修复的/ -有的错误是用户输入造成的,比如让用户输入email地址,结果得到一个空字符串,这种错误可以通过检查用户输入来做相应的处理。 -还有一类错误是完全无法在程序运行过程中预测的,比如写入文件的时候,磁盘满了,写不进去了,或者从网络抓取数据,网络突然断掉了。这类错误也称为异常,在程序中通常是必须处理的,否则,程序会因为各种问题终止并退出。 -ython内置了一套异常处理机制,来帮助我们进行错误处理。 -此外,我们也需要跟踪程序的执行,查看变量的值是否正确,这个过程称为调试。Python的pdb可以让我们以单步方式执行代码。 -最后,编写测试也很重要。有了良好的测试,就可以在程序修改后反复运行,确保程序输出符合我们编写的测试。 - -高级语言通常都内置了一套try...except...finally... - diff --git a/2017-04-28/stmp_text/1.txt b/2017-04-28/stmp_text/1.txt deleted file mode 100644 index 1ac4e95..0000000 --- a/2017-04-28/stmp_text/1.txt +++ /dev/null @@ -1,2 +0,0 @@ -smtp.qiye.163.com -smtp.163.com diff --git a/2017-04-28/stmp_text/cookies.dat b/2017-04-28/stmp_text/cookies.dat deleted file mode 100644 index 4d7acd3..0000000 --- a/2017-04-28/stmp_text/cookies.dat +++ /dev/null @@ -1 +0,0 @@ -#LWP-Cookies-2.0 diff --git a/2017-04-28/stmp_text/send.py b/2017-04-28/stmp_text/send.py deleted file mode 100644 index 1d165d0..0000000 --- a/2017-04-28/stmp_text/send.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -from email import encoders -from email.header import Header -from email.mime.text import MIMEText -from email.utils import parseaddr, formataddr -import smtplib - -def _format_addr(s): - name, addr = parseaddr(s) - return formataddr(( \ - Header(name, 'utf-8').encode(), \ - addr.encode('utf-8') if isinstance(addr, unicode) else addr)) - -from_addr = raw_input('From: ') -password = raw_input('Password: ') -to_addr = raw_input('To: ') -smtp_server = raw_input('SMTP server: ') - -msg = MIMEText('hello, send by Python...', 'plain', 'utf-8') -msg['From'] = _format_addr(u'Python爱好者 <%s>' % from_addr) -msg['To'] = _format_addr(u'管理员 <%s>' % to_addr) -msg['Subject'] = Header(u'来自SMTP的问候……', 'utf-8').encode() - -server = smtplib.SMTP(smtp_server, 25) -server.set_debuglevel(1) -server.login(from_addr, password) -server.sendmail(from_addr, [to_addr], msg.as_string()) -server.quit() diff --git a/2017-04-28/stmp_text/sendM.py b/2017-04-28/stmp_text/sendM.py deleted file mode 100644 index cce702a..0000000 --- a/2017-04-28/stmp_text/sendM.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- - -from email import encoders -from email.header import Header -from email.mime.text import MIMEText -from email.mime.base import MIMEBase -from email.mime.multipart import MIMEMultipart -from email.utils import parseaddr, formataddr - -import smtplib - -def _format_addr(s): - name, addr = parseaddr(s) - return formataddr(( \ - Header(name, 'utf-8').encode(), \ - addr.encode('utf-8') if isinstance(addr, unicode) else addr)) - -from_addr = raw_input('From: ') -password = raw_input('Password: ') -to_addr = raw_input('To: ') -smtp_server = raw_input('SMTP server: ') - -msg = MIMEMultipart() -msg['From'] = _format_addr(u'康晓宇 <%s>' % from_addr) -msg['To'] = _format_addr(u'kehai <%s>' % to_addr) -msg['Subject'] = Header(u'2017年04月第04周工作总结【康晓宇】','utf-8').encode() - -# add MIMEText: -msg.attach(MIMEText('2017年04月第04周工作总结','plain', 'utf-8')) - -# add file: -with open('/root/report/2017年04月第04周工作总结【康晓宇】.xlsx','rb') as f: - mime = MIMEBase('image', 'png', filename='test.png') - mime.add_header('Content-Disposition', 'attachment', filename='test.xlsx') - mime.add_header('Content-ID', '<0>') - mime.add_header('X-Attachment-Id', '0') - mime.set_payload(f.read()) - encoders.encode_base64(mime) - msg.attach(mime) - -server = smtplib.SMTP(smtp_server, 25) -server.set_debuglevel(1) -server.login(from_addr, password) -server.sendmail(from_addr, [to_addr], msg.as_string()) -server.quit() diff --git a/2017-04-28/stmp_text/sendReport.py b/2017-04-28/stmp_text/sendReport.py deleted file mode 100644 index 599df0a..0000000 --- a/2017-04-28/stmp_text/sendReport.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- - -from email import encoders -from email.header import Header -from email.mime.text import MIMEText -from email.mime.base import MIMEBase -from email.mime.multipart import MIMEMultipart -from email.utils import parseaddr, formataddr -import smtplib - -def _format_addr(s): - name, addr = parseaddr(s) - return formataddr(( \ - Header(name, 'utf-8').encode(), \ - addr.encode('utf-8') if isinstance(addr, unicode) else addr)) - -from_addr = raw_input('From: ') -password = raw_input('Password: ') -to_addr = raw_input('To: ') -smtp_server = raw_input('SMTP server: ') - -# 邮件对象: -msg = MIMEMultipart() -msg['From'] = _format_addr(u'Python爱好者 <%s>' % from_addr) -msg['To'] = _format_addr(u'管理员 <%s>' % to_addr) -msg['Subject'] = Header(u'来自SMTP的问候……', 'utf-8').encode() - -# 邮件正文是MIMEText: -msg.attach(MIMEText('send with file...', 'plain', 'utf-8')) - -# 添加附件就是加上一个MIMEBase,从本地读取一个图片: -with open('/root/report/test.xlsx', 'rb') as f: - # 设置附件的MIME和文件名,这里是png类型: - mime = MIMEBase('image', 'png', filename='test.png') - # 加上必要的头信息: - mime.add_header('Content-Disposition', 'attachment', filename='test.xlsx') - mime.add_header('Content-ID', '<0>') - mime.add_header('X-Attachment-Id', '0') - # 把附件的内容读进来: - mime.set_payload(f.read()) - # 用Base64编码: - encoders.encode_base64(mime) - # 添加到MIMEMultipart: - msg.attach(mime) diff --git a/2017-04-28/unitest/mydict.py b/2017-04-28/unitest/mydict.py deleted file mode 100644 index 84f4c85..0000000 --- a/2017-04-28/unitest/mydict.py +++ /dev/null @@ -1,13 +0,0 @@ -class Dict(dict): - - def __init__(self, **kw): - super(Dict, self).__init__(**kw) - - def __getattr__(self, key): - try: - return self[key] - except KeyError: - raise AttributeError(r"'Dict' object has no attribute '%s'" % key) - - def __setattr__(self, key, value): - self[key] = value diff --git a/2017-04-28/unitest/mydict.pyc b/2017-04-28/unitest/mydict.pyc deleted file mode 100644 index 0e338c6..0000000 Binary files a/2017-04-28/unitest/mydict.pyc and /dev/null differ diff --git a/2017-04-28/unitest/test.py b/2017-04-28/unitest/test.py deleted file mode 100644 index 950d4b2..0000000 --- a/2017-04-28/unitest/test.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest - -from mydict import Dict - -class TestDict(unittest.TestCase): - - def test_init(self): - d = Dict(a=1, b='test') - self.assertEquals(d.a, 1) - self.assertEquals(d.b, 'test') - self.assertTrue(isinstance(d, dict)) - - def test_key(self): - d = Dict() - d['key'] = 'value' - self.assertEquals(d.key, 'value') - - def test_attr(self): - d = Dict() - d.key = 'value' - self.assertTrue('key' in d) - self.assertEquals(d['key'], 'value') - - def test_keyerror(self): - d = Dict() - with self.assertRaises(KeyError): - value = d['empty'] - - def test_attrerror(self): - d = Dict() - with self.assertRaises(AttributeError): - value = d.empty -if __name__ == '__main__': - unittest.main() diff --git a/2017-05-02/file_r_w/f_file.py b/2017-05-02/file_r_w/f_file.py deleted file mode 100644 index fec6d87..0000000 --- a/2017-05-02/file_r_w/f_file.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -try: - with open('/root/test.txt','r') as f: - for line in f.readlines(): - print(line.strip()) -finally: - if f: - f.close() diff --git a/2017-05-02/file_r_w/f_file_jpg.py b/2017-05-02/file_r_w/f_file_jpg.py deleted file mode 100644 index eff93d7..0000000 --- a/2017-05-02/file_r_w/f_file_jpg.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -try: - with open('/root/python275/python_execise/2017-05-02/file_r_w/timg.jpg','rb') as f: - for line in f.readlines(): - print(line.strip()) -finally: - if f: - f.close() diff --git a/2017-05-02/file_r_w/test.txt b/2017-05-02/file_r_w/test.txt deleted file mode 100644 index 2889c67..0000000 --- a/2017-05-02/file_r_w/test.txt +++ /dev/null @@ -1 +0,0 @@ -Hello,world! \ No newline at end of file diff --git a/2017-05-02/file_r_w/timg.jpg b/2017-05-02/file_r_w/timg.jpg deleted file mode 100644 index eb123b2..0000000 Binary files a/2017-05-02/file_r_w/timg.jpg and /dev/null differ diff --git a/2017-05-02/file_r_w/w_file.py b/2017-05-02/file_r_w/w_file.py deleted file mode 100644 index 2f045f6..0000000 --- a/2017-05-02/file_r_w/w_file.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -with open('test.txt','w') as f: - f.write('Hello,world!') diff --git a/2017-05-02/json/.json_student.py.swp b/2017-05-02/json/.json_student.py.swp deleted file mode 100644 index 33e2509..0000000 Binary files a/2017-05-02/json/.json_student.py.swp and /dev/null differ diff --git a/2017-05-02/json/Student_json.py/Student.py b/2017-05-02/json/Student_json.py/Student.py deleted file mode 100644 index 74bc584..0000000 --- a/2017-05-02/json/Student_json.py/Student.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import json -class Student(object): - def __init__(self,name,age,score): - self.name = name - self.age = age - self.score = score -s = Student('Bob',20,88) -print(json.dumps(s)) diff --git a/2017-05-02/json/Student_json.py/dict2student.py b/2017-05-02/json/Student_json.py/dict2student.py deleted file mode 100644 index 5e3e9a8..0000000 --- a/2017-05-02/json/Student_json.py/dict2student.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import json - -class Student(object): - def __init__(self,name,age,score): - self.name = name - self.age = age - self.score =score -def dict2student(d): - return Student(d['name'],d['age'],d['score']) -json_str='{"age":20,"score":88,"name":"Bob"}' -print(json.loads(json_str,object_hook=dict2student)) diff --git a/2017-05-02/json/Student_json.py/student2dict.py b/2017-05-02/json/Student_json.py/student2dict.py deleted file mode 100644 index 0d316ed..0000000 --- a/2017-05-02/json/Student_json.py/student2dict.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import json -class Student(object): - def __init__(self,name,age,score): - self.name = name - self.age = age - self.score = score -s=Student=('Bob',20,88) -def student2dict(std): - return { - 'name':std.name, - 'age':std.age, - 'score':std.score - } -print(json.dumps(s,default=student2dict)) diff --git a/2017-05-02/json/Student_json.py/student_json.py b/2017-05-02/json/Student_json.py/student_json.py deleted file mode 100644 index 09703b3..0000000 --- a/2017-05-02/json/Student_json.py/student_json.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import json -def student2dict(std): - return{ - 'name':std.name, - 'age':std.age, - 'score':std.score - } -s = student2dict({'name':'kxy','age':80,'score':77}) -print(json.dumps(s,default=student2dict)) - diff --git a/2017-05-02/json/json_test.py b/2017-05-02/json/json_test.py deleted file mode 100644 index 5ddc55d..0000000 --- a/2017-05-02/json/json_test.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -import json -d = dict(name='Bob',age=20,score=88) -print json.dumps(d) diff --git a/2017-05-02/json/json_test1.py b/2017-05-02/json/json_test1.py deleted file mode 100644 index 799be15..0000000 --- a/2017-05-02/json/json_test1.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/env python -import json -json_str='{"age":20,"score":88,"name":"Bob"}' -print json.loads(json_str) diff --git a/2017-05-02/operator_file_dir/os_name.py b/2017-05-02/operator_file_dir/os_name.py deleted file mode 100644 index 80f42c0..0000000 --- a/2017-05-02/operator_file_dir/os_name.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import os -print os.name -print os.uname() -print os.environ -print os.getenv('PATH') diff --git a/2017-05-02/operator_file_dir/os_path.py b/2017-05-02/operator_file_dir/os_path.py deleted file mode 100644 index f6b3670..0000000 --- a/2017-05-02/operator_file_dir/os_path.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import os -print os.path.abspath('.') -print os.path.join('/root/bin','testdir') -os.mkdir('/root/bin/testdir') -#os.rmdir('/root/bin/testdir') diff --git a/2017-05-02/process_threading/.Pool.py.swp b/2017-05-02/process_threading/.Pool.py.swp deleted file mode 100644 index d1e20b4..0000000 Binary files a/2017-05-02/process_threading/.Pool.py.swp and /dev/null differ diff --git a/2017-05-02/process_threading/Pool.py b/2017-05-02/process_threading/Pool.py deleted file mode 100644 index a9b529f..0000000 --- a/2017-05-02/process_threading/Pool.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from multiprocessing import Pool -import os, time,random -def long_time_task(name): - print ('Run task %s (%s)...', % (name,os.getpid())) - start = time.time() - time.sleep(random.random()*3) - end = time.time() - print ('Task %s runs %0.2f seconds.', % (name,(end-start))) -if __name__=='__main__': - print ('Parent process %s.', % os.getpid()) - p = Pool() - for i in range(5): - p.apply_async(long_time_task,args=(i,)) - print ('Waiting for all subprocesses done...') - p.close() - p.join() - print ('All subprocesses done/') diff --git a/2017-05-02/process_threading/multiprocessing.py b/2017-05-02/process_threading/multiprocessing.py deleted file mode 100644 index 08a08cc..0000000 --- a/2017-05-02/process_threading/multiprocessing.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import os -print 'Process (%s) start...' % os.getpid() -pid = os.fork() -if pid == 0: - print 'I am child process (%s) and my parent is %s.' % (os.getpid(),os.getppid()) -else: - print 'I (%s) just create a child process(%s).' % (os.getpid(),pid) - diff --git a/2017-05-02/process_threading/multiprocessing.pyc b/2017-05-02/process_threading/multiprocessing.pyc deleted file mode 100644 index 8d370d8..0000000 Binary files a/2017-05-02/process_threading/multiprocessing.pyc and /dev/null differ diff --git a/2017-05-02/process_threading/multiprocessing_part.py b/2017-05-02/process_threading/multiprocessing_part.py deleted file mode 100644 index 632422f..0000000 --- a/2017-05-02/process_threading/multiprocessing_part.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from multiprocessing import Process -import os - -def run_proc(name): - print 'Run child process %s (%s)...' % (name,os.getpid()) -if __name__ =='__main__': - print 'Parent process %s.' % os.getpid() - p = Process(target=run_proc,args=('test',)) - print 'Process will start.' - p.start() - p.join() - print 'Process end.' - diff --git a/2017-05-02/serilize/dump.txt b/2017-05-02/serilize/dump.txt deleted file mode 100644 index d5a55d6..0000000 --- a/2017-05-02/serilize/dump.txt +++ /dev/null @@ -1,12 +0,0 @@ -(dp1 -S'age' -p2 -I20 -sS'score' -p3 -I88 -sS'name' -p4 -S'Bob' -p5 -s. \ No newline at end of file diff --git a/2017-05-02/serilize/read_serial.py b/2017-05-02/serilize/read_serial.py deleted file mode 100644 index f31d661..0000000 --- a/2017-05-02/serilize/read_serial.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -import pickle -f=open('dump.txt','rb') -d=pickle.load(f) -f.close() -print d diff --git a/2017-05-02/serilize/serial.py b/2017-05-02/serilize/serial.py deleted file mode 100644 index d65cea9..0000000 --- a/2017-05-02/serilize/serial.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -try: - import cPickle as pickle -except ImportError: - import pickle -d =dict(name='Bob', age=20, score=88) -f = open('/root/python275/python_execise/2017-05-02/serilize/dump.txt','wb') -pickle.dump(d,f) -f.close() diff --git a/2017-05-02/threading/ocr_threading.txt b/2017-05-02/threading/ocr_threading.txt deleted file mode 100644 index 6b24f43..0000000 --- a/2017-05-02/threading/ocr_threading.txt +++ /dev/null @@ -1,23 +0,0 @@ -import time,threading -# -*- coding:utf-8 -*- -import time,threading -# 假定这是你的银行存款: -balance = 0 -def change_it(n): - #先存后取,结果应该为8 - global balance - balance = balance + n - balance = balance -n -def run_thread(n): - for i in range(100000): - change_it(n) -t1 = threading.Thread(target=run_thread,args=(5,)) -t2 = threading.Thread(target=run_thread,args=(8,)) -t1.start() -t2.start() -t1.join() -t2.join() -print balance - - - diff --git a/2017-05-02/threading/thread1.py b/2017-05-02/threading/thread1.py deleted file mode 100644 index 2fc8e06..0000000 --- a/2017-05-02/threading/thread1.py +++ /dev/null @@ -1,15 +0,0 @@ -import time,threading - -def loop(): - print 'thread %s is running...' % threading.current_thread().name - n = 0 - while n < 5: - n = n + 1 - print 'thread %s >>> %s' % (threading.current_thread().name,n) - time.sleep(1) - print 'thread %s ended.' % threading.current_thread().name -print 'thread %s is running...' % threading.current_thread().name -t = threading.Thread(target=loop,name='LoopThread') -t.start() -t.join() -print 'thread %s ended.' % threading.current_thread().name diff --git a/2017-05-02/threadlocal/local.py b/2017-05-02/threadlocal/local.py deleted file mode 100644 index 4211288..0000000 --- a/2017-05-02/threadlocal/local.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -class Student(object): - def __init__(self,name,age,score): - self.name = name - self.age = age - self.score= score -def process_student(name): - std = Student(name) - do_task_1(std) - do_task_2(std) - -def do_task_1(std): - do_subtask_1(std) - do_subtask_2(std) -def do_task_2(std): - do_subtask_2(std) - do_subtask_2(std) -global_dict = {} -def std_thread(name): - std = Student(name) - global_dict[threading.current_thread()] = std - do_task_1() - do_task_2() -def do_task_1(): - std = global_dict[threading.current_thread()] -def do_task_2(): - std = global_dict[threading.current_thread()] -import threading - -local_school=threading.local() -def process_student(): - print 'Hello. %s (in %s)' % (local_school.student,threading.current_thread().name) -def process_thread(name): - local_school.student = name - process_student() -t1 = threading.Thread(target=process_thread,args=('Alice',),name='Thread_A') -t2 = threading.Thread(target=process_thread, args=('Bob',),name='Thread_B') - -t1.start() -t2.start() -t1.join() -t2.join() - diff --git a/2017-05-02/threadlocal/task.txt b/2017-05-02/threadlocal/task.txt deleted file mode 100644 index 5aa1f67..0000000 --- a/2017-05-02/threadlocal/task.txt +++ /dev/null @@ -1,15 +0,0 @@ -这个简单的Manager/Worker模型有什么用?其实这就是一个简单但真正的分布式计算,把代码稍加改造,启动多个worker,就可以把任务分布到几台甚至几十台机器上,比如把计算n*n的代码换成发送邮件,就实现了邮件队列的异步发送。 - -Queue对象存储在哪?注意到taskworker.py中根本没有创建Queue的代码,所以,Queue对象存储在taskmanager.py进程中: - -分布式进程 - -而Queue之所以能通过网络访问,就是通过QueueManager实现的。由于QueueManager管理的不止一个Queue,所以,要给每个Queue的网络调用接口起个名字,比如get_task_queue。 - -authkey有什么用?这是为了保证两台机器正常通信,不被其他机器恶意干扰。如果taskworker.py的authkey和taskmanager.py的authkey不一致,肯定连接不上。 - -小结 - -Python的分布式进程接口简单,封装良好,适合需要把繁重任务分布到多台机器的环境下。 - -注意Queue的作用是用来传递任务和接收结果,每个任务的描述数据量要尽量小。比如发送一个处理日志文件的任务,就不要发送几百兆的日志文件本身,而是发送日志文件存放的完整路径,由Worker进程再去共享的磁盘上读取文件。 diff --git a/2017-05-02/threadlocal/taskManager.py b/2017-05-02/threadlocal/taskManager.py deleted file mode 100644 index 96f367b..0000000 --- a/2017-05-02/threadlocal/taskManager.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/ehv python -# -*- coding:utf-8 -*- -import random,time,Queue -from multiprocessing.managers import BaseManager - -# 发送任务的队列 -task_queue = Queue.Queue() -result_queue = Queue.Queue() -class QueueManager(BaseManager): - pass -QueueManager.register('get_task_queue',callable=lambda:task_queue) -QueueManager.register('get_result_queue',callable=lambda:result_queue) -manager = QueueManager(address=('127.0.0.1',5000),authkey='abc') -#启动Queue -manager.start() -#获得通过网络访问的Queue对象 -task = manager.get_task_queue() -result = manager.get_result_queue() -#放几个任务进去 -for i in range(10): - n = random.randint(0,10000) - print('Put task %d...' % n) - task.put(n) -print('Try get results...') -for i in range(10): - r = result.get(timeout=10) - print('Result:%s' % r) -manager.shutdown() diff --git a/2017-05-02/threadlocal/taskworker.py b/2017-05-02/threadlocal/taskworker.py deleted file mode 100644 index 0f9bc1c..0000000 --- a/2017-05-02/threadlocal/taskworker.py +++ /dev/null @@ -1,26 +0,0 @@ -# taskworker.py -#!/bin/env python -import time,sys,Queue -#-*- coding:utf-8 -*- -from multiprocessing.managers import BaseManager -class QueueManager(BaseManager): - pass -QueueManager.register('get_task_queue') -QueueManager.register('get_result_queue') - -server_addr = '127.0.0.1' -print ('Connect to server %s...' % server_addr) -m = QueueManager(address=(server_addr,5000),authkey='abc') -m.connect() -task = m.get_task_queue() -result = m.get_result_queue() -for i in range(10): - try: - n = task.get(timeout=1) - print('run task %d * %d...' % (n,n)) - r = '%d * %d = %d' % (n,n,n*n) - time.sleep(1) - result.put(r) - except Queue.Empty: - print('task queue is empty.') -print('worker exit.') diff --git a/bubblesort.py b/bubblesort.py deleted file mode 100755 index e6014d6..0000000 --- a/bubblesort.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python -import datetime -print datetime.datetime.now() - -from random import randint -mylist = [2,45,12,75,82,102] - -for times in range(0,100): - number = (randint(0,10000)) - mylist.append(number) - -for idx in range(len(mylist)-1): - for idx2 in range(len(mylist)-1): - if mylist[idx2] > mylist[idx2+1]: - temp = mylist[idx2] - mylist[idx2] = mylist[idx2+1] - mylist[idx2+1] = temp -print mylist -print datetime.datetime.now() diff --git a/continue_break/continue.py b/continue_break/continue.py deleted file mode 100644 index 5274e41..0000000 --- a/continue_break/continue.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -def cont(): - for i in range(1,6): - if i == 3: - continue - else: - print i -def func(a,b): - print a + b - -if __name__ =="__main__": -# print("main") -# func(1,2,3)i - - diff --git a/continue_break/pytho.py b/continue_break/pytho.py deleted file mode 100644 index 42fa985..0000000 --- a/continue_break/pytho.py +++ /dev/null @@ -1,8 +0,0 @@ -class Student(object): - def __init__(self,name,score): - self.name = name - self.score= score - def print_score(self): - print('%s:%s' % (self.name, self.score)) -bart = Student("kxy",30) -bart.print_score() diff --git "a/doc/20170421/\345\256\232\344\271\211\345\207\275\346\225\260.txt" "b/doc/20170421/\345\256\232\344\271\211\345\207\275\346\225\260.txt" deleted file mode 100644 index 763d905..0000000 --- "a/doc/20170421/\345\256\232\344\271\211\345\207\275\346\225\260.txt" +++ /dev/null @@ -1,3 +0,0 @@ -在Python中,定义一个函数要使用def语句, - -依次写出函数名,括号,括号中的参数和冒号:, diff --git "a/doc/20170422/.\345\217\257\345\217\230\345\217\202\346\225\260.txt.swp" "b/doc/20170422/.\345\217\257\345\217\230\345\217\202\346\225\260.txt.swp" deleted file mode 100644 index 37197f5..0000000 Binary files "a/doc/20170422/.\345\217\257\345\217\230\345\217\202\346\225\260.txt.swp" and /dev/null differ diff --git "a/doc/20170422/\344\275\215\347\275\256\345\217\202\346\225\260.txt" "b/doc/20170422/\344\275\215\347\275\256\345\217\202\346\225\260.txt" deleted file mode 100644 index d712cd6..0000000 --- "a/doc/20170422/\344\275\215\347\275\256\345\217\202\346\225\260.txt" +++ /dev/null @@ -1,3 +0,0 @@ -位置参数的概念: - 位置参数是按照差数的顺序传入的 -修改后的power(x, n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n diff --git "a/doc/20170422/\345\205\263\351\224\256\345\255\227\345\217\202\346\225\260.txt" "b/doc/20170422/\345\205\263\351\224\256\345\255\227\345\217\202\346\225\260.txt" deleted file mode 100644 index 8795a6c..0000000 --- "a/doc/20170422/\345\205\263\351\224\256\345\255\227\345\217\202\346\225\260.txt" +++ /dev/null @@ -1,26 +0,0 @@ -可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例: - -def person(name, age, **kw): - print('name:', name, 'age:', age, 'other:', kw) -函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数: - ->>> person('Michael', 30) -name: Michael age: 30 other: {} -也可以传入任意个数的关键字参数: - ->>> person('Bob', 35, city='Beijing') -name: Bob age: 35 other: {'city': 'Beijing'} ->>> person('Adam', 45, gender='M', job='Engineer') -name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'} -关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。 - -和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去: - ->>> extra = {'city': 'Beijing', 'job': 'Engineer'} ->>> person('Jack', 24, city=extra['city'], job=extra['job']) -name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'} -当然,上面复杂的调用可以用简化的写法: - ->>> extra = {'city': 'Beijing', 'job': 'Engineer'} ->>> person('Jack', 24, **extra) -name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'} diff --git "a/doc/20170422/\345\205\263\351\224\256\345\255\227\345\217\202\346\225\2601.txt" "b/doc/20170422/\345\205\263\351\224\256\345\255\227\345\217\202\346\225\2601.txt" deleted file mode 100644 index 7d28051..0000000 --- "a/doc/20170422/\345\205\263\351\224\256\345\255\227\345\217\202\346\225\2601.txt" +++ /dev/null @@ -1,23 +0,0 @@ -可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple,而关键字参数允许你传入0个或任意个含(参数名的 -参数),这些关键字参数在函数内部自动组装为一个dict. - -def person(name,age,**kw): - print('name:',name,'age:',age,'other',kw) - -person('Michael',30 - -def person(name,age,**kw): - print('name:',name,'age:',age,'other:',kw) - -extra = {'city':'Beijing','job':'Engineer'} -person('jack',24,**extra) - -def person(name,age,**kw): -... print('name:',name,'age:',age,'other:',kw) -... ->>> extra = {'city':'Beijing','job':'Engineer'} ->>> person('jack',24,**extra) -('name:', 'jack', 'age:', 24, 'other:', {'city': 'Beijing', 'job': 'Engineer'}) -**extra表示把extra这个dict的所有key-value用关键字传入到函数的**kw参数, kw将获得一个dict,kw将获得一个dict,注意kw获得的dict是 -extra的一份拷贝,对kw的改动不会影响到函数外的extra. - diff --git "a/doc/20170422/\345\207\275\346\225\260.txt" "b/doc/20170422/\345\207\275\346\225\260.txt" deleted file mode 100644 index 1389b41..0000000 --- "a/doc/20170422/\345\207\275\346\225\260.txt" +++ /dev/null @@ -1,5 +0,0 @@ -要调用一个函数,需要知道函数的名称和参数, 比如求绝对值的函数abs, -只有一个参数, 可以i -函数名其实就是指向一个函数对象的引用,完全可以把函数名赋予一个变量, -相当于给这个函数起了一个别名。 - diff --git "a/doc/20170422/\345\207\275\346\225\260\345\217\202\346\225\260\347\232\204\345\210\206\347\261\273.txt" "b/doc/20170422/\345\207\275\346\225\260\345\217\202\346\225\260\347\232\204\345\210\206\347\261\273.txt" deleted file mode 100644 index dae7b28..0000000 --- "a/doc/20170422/\345\207\275\346\225\260\345\217\202\346\225\260\347\232\204\345\210\206\347\261\273.txt" +++ /dev/null @@ -1,2 +0,0 @@ - -默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。 diff --git "a/doc/20170422/\345\207\275\346\225\260\347\232\204\345\217\202\346\225\260.txt" "b/doc/20170422/\345\207\275\346\225\260\347\232\204\345\217\202\346\225\260.txt" deleted file mode 100644 index da3f520..0000000 --- "a/doc/20170422/\345\207\275\346\225\260\347\232\204\345\217\202\346\225\260.txt" +++ /dev/null @@ -1,15 +0,0 @@ -定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道 -如何传递正常的参数,以及函数将返回什么样的值就够了。函数内部的复杂逻辑被封装起来。调用者无需了解。 - -Python的函数定义非常简单。 但灵活度却非常大,除了正常定义的必选参数外,(还可以使用默认参数。可变参数和关键字参数。 -使得函数定义出来的接口, 不但能处理复杂的参数,还可以简化调用者的代码。 - -位置参数 -我们先写一个计算xx的函数。 - -def power(x): - return x*x - -脚本不用声明类型。 -a =1 -a = 'bj' diff --git "a/doc/20170422/\345\217\202\346\225\260\347\273\204\345\220\210.txt" "b/doc/20170422/\345\217\202\346\225\260\347\273\204\345\220\210.txt" deleted file mode 100644 index 8d24157..0000000 --- "a/doc/20170422/\345\217\202\346\225\260\347\273\204\345\220\210.txt" +++ /dev/null @@ -1,37 +0,0 @@ -def f1(a,b,c=0,*args,**kw): - print('a=', a, 'b=',b,'c=',c,'args=',args,'kw=',kw) - - args = (1, 2, 3, 4) ->>> kw = {'d': 99, 'x': '#'} ->>> f1(*args, **kw) -a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'} ->>> args = (1, 2, 3) ->>> kw = {'d': 88, 'x': '#'} ->>> f2(*args, **kw) -a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'} -所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。 - -小结 - -Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。 - -默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误! - -要注意定义可变参数和关键字参数的语法: - -*args是可变参数,args接收的是一个tuple; - -**kw是关键字参数,kw接收的是一个dict。 - -以及调用函数时如何传入可变参数和关键字参数的语法: - -可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3)); - -关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})。 - -使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。 - -命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。 - -定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。 - diff --git "a/doc/20170422/\345\217\257\345\217\230\345\217\202\346\225\260.txt" "b/doc/20170422/\345\217\257\345\217\230\345\217\202\346\225\260.txt" deleted file mode 100644 index c76bd0c..0000000 --- "a/doc/20170422/\345\217\257\345\217\230\345\217\202\346\225\260.txt" +++ /dev/null @@ -1,51 +0,0 @@ - -g - 1 可变参数 - 2 在Python函数中,还可以定义可变参数,顾名思义, 可变参数就是传入的参数个数是可变的。 - 3 参数是列表的是可变参数 -i - -def calc(numbers): - sum = 0 - for n in numbers: - sum = sum + n*n -i return sum~ - -> def calc(numbers): -... sum = 0 -... for n in numbers: -... sum = sum + n * n -... return sum -... ->>> calc([1,2,3]) -14 ->>> calc((1,3,5,7)) - - -所以,我们把函数的参数改为可变参数: - -def calc(*numbers): - sum = 0 - for n in numbers: - sum = sum + n * n - return sum -定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数: - ->>> calc(1, 2) -5 ->>> calc() -0 -如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做: - ->>> nums = [1, 2, 3] ->>> calc(nums[0], nums[1], nums[2]) -14 -这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去: - ->>> nums = [1, 2, 3] ->>> calc(*nums) -14 -*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。 - -关键字参数 -*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。 diff --git "a/doc/20170422/\345\221\275\345\220\215\345\205\263\351\224\256\345\255\227\345\217\202\346\225\260.txt" "b/doc/20170422/\345\221\275\345\220\215\345\205\263\351\224\256\345\255\227\345\217\202\346\225\260.txt" deleted file mode 100644 index 9190c6a..0000000 --- "a/doc/20170422/\345\221\275\345\220\215\345\205\263\351\224\256\345\255\227\345\217\202\346\225\260.txt" +++ /dev/null @@ -1,259 +0,0 @@ -函数的参数 - -阅读: 491952 -定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。 - -Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。 - -位置参数 - -我们先写一个计算x2的函数: - -def power(x): - return x * x -对于power(x)函数,参数x就是一个位置参数。 - -当我们调用power函数时,必须传入有且仅有的一个参数x: - ->>> power(5) -25 ->>> power(15) -225 -现在,如果我们要计算x3怎么办?可以再定义一个power3函数,但是如果要计算x4、x5……怎么办?我们不可能定义无限多个函数。 - -你也许想到了,可以把power(x)修改为power(x, n),用来计算xn,说干就干: - -def power(x, n): - s = 1 - while n > 0: - n = n - 1 - s = s * x - return s -对于这个修改后的power(x, n)函数,可以计算任意n次方: - ->>> power(5, 2) -25 ->>> power(5, 3) -125 -修改后的power(x, n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。 - -默认参数 - -新的power(x, n)函数定义没有问题,但是,旧的调用代码失败了,原因是我们增加了一个参数,导致旧的代码因为缺少一个参数而无法正常调用: - ->>> power(5) -Traceback (most recent call last): - File "", line 1, in -TypeError: power() missing 1 required positional argument: 'n' -Python的错误信息很明确:调用函数power()缺少了一个位置参数n。 - -这个时候,默认参数就排上用场了。由于我们经常计算x2,所以,完全可以把第二个参数n的默认值设定为2: - -def power(x, n=2): - s = 1 - while n > 0: - n = n - 1 - s = s * x - return s -这样,当我们调用power(5)时,相当于调用power(5, 2): - ->>> power(5) -25 ->>> power(5, 2) -25 -而对于n > 2的其他情况,就必须明确地传入n,比如power(5, 3)。 - -从上面的例子可以看出,默认参数可以简化函数的调用。设置默认参数时,有几点要注意: - -一是必选参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面); - -二是如何设置默认参数。 - -当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。 - -使用默认参数有什么好处?最大的好处是能降低调用函数的难度。 - -举个例子,我们写个一年级小学生注册的函数,需要传入name和gender两个参数: - -def enroll(name, gender): - print('name:', name) - print('gender:', gender) -这样,调用enroll()函数只需要传入两个参数: - ->>> enroll('Sarah', 'F') -name: Sarah -gender: F -如果要继续传入年龄、城市等信息怎么办?这样会使得调用函数的复杂度大大增加。 - -我们可以把年龄和城市设为默认参数: - -def enroll(name, gender, age=6, city='Beijing'): - print('name:', name) - print('gender:', gender) - print('age:', age) - print('city:', city) -这样,大多数学生注册时不需要提供年龄和城市,只提供必须的两个参数: - ->>> enroll('Sarah', 'F') -name: Sarah -gender: F -age: 6 -city: Beijing -只有与默认参数不符的学生才需要提供额外的信息: - -enroll('Bob', 'M', 7) -enroll('Adam', 'M', city='Tianjin') -可见,默认参数降低了函数调用的难度,而一旦需要更复杂的调用时,又可以传递更多的参数来实现。无论是简单调用还是复杂调用,函数只需要定义一个。 - -有多个默认参数时,调用的时候,既可以按顺序提供默认参数,比如调用enroll('Bob', 'M', 7),意思是,除了name,gender这两个参数外,最后1个参数应用在参数age上,city参数由于没有提供,仍然使用默认值。 - -也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。比如调用enroll('Adam', 'M', city='Tianjin'),意思是,city参数用传进去的值,其他默认参数继续使用默认值。 - -默认参数很有用,但使用不当,也会掉坑里。默认参数有个最大的坑,演示如下: - -先定义一个函数,传入一个list,添加一个END再返回: - -def add_end(L=[]): - L.append('END') - return L -当你正常调用时,结果似乎不错: - ->>> add_end([1, 2, 3]) -[1, 2, 3, 'END'] ->>> add_end(['x', 'y', 'z']) -['x', 'y', 'z', 'END'] -当你使用默认参数调用时,一开始结果也是对的: - ->>> add_end() -['END'] -但是,再次调用add_end()时,结果就不对了: - ->>> add_end() -['END', 'END'] ->>> add_end() -['END', 'END', 'END'] -很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了'END'后的list。 - -原因解释如下: - -Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。 - -所以,定义默认参数要牢记一点:默认参数必须指向不变对象! - -要修改上面的例子,我们可以用None这个不变对象来实现: - -def add_end(L=None): - if L is None: - L = [] - L.append('END') - return L -现在,无论调用多少次,都不会有问题: - ->>> add_end() -['END'] ->>> add_end() -['END'] -为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。 - -可变参数 - -在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。 - -我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。 - -要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下: - -def calc(numbers): - sum = 0 - for n in numbers: - sum = sum + n * n - return sum -但是调用的时候,需要先组装出一个list或tuple: - ->>> calc([1, 2, 3]) -14 ->>> calc((1, 3, 5, 7)) -84 -如果利用可变参数,调用函数的方式可以简化成这样: - ->>> calc(1, 2, 3) -14 ->>> calc(1, 3, 5, 7) -84 -所以,我们把函数的参数改为可变参数: - -def calc(*numbers): - sum = 0 - for n in numbers: - sum = sum + n * n - return sum -定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数: - ->>> calc(1, 2) -5 ->>> calc() -0 -如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做: - ->>> nums = [1, 2, 3] ->>> calc(nums[0], nums[1], nums[2]) -14 -这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去: - ->>> nums = [1, 2, 3] ->>> calc(*nums) -14 -*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。 - -关键字参数 - -可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例: - -def person(name, age, **kw): - print('name:', name, 'age:', age, 'other:', kw) -函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数: - ->>> person('Michael', 30) -name: Michael age: 30 other: {} -也可以传入任意个数的关键字参数: - ->>> person('Bob', 35, city='Beijing') -name: Bob age: 35 other: {'city': 'Beijing'} ->>> person('Adam', 45, gender='M', job='Engineer') -name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'} -关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。 - -和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去: - ->>> extra = {'city': 'Beijing', 'job': 'Engineer'} ->>> person('Jack', 24, city=extra['city'], job=extra['job']) -name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'} -当然,上面复杂的调用可以用简化的写法: - ->>> extra = {'city': 'Beijing', 'job': 'Engineer'} ->>> person('Jack', 24, **extra) -name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'} -**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。 - -命名关键字参数 - -对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。 - -仍以person()函数为例,我们希望检查是否有city和job参数: - -def person(name, age, **kw): - if 'city' in kw: - # 有city参数 - pass - if 'job' in kw: - # 有job参数 - pass - print('name:', name, 'age:', age, 'other:', kw) -但是调用者仍可以传入不受限制的关键字参数: - ->>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456) -如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下: - -def person(name, age, *, city, job): - print(name, age, city, job) -和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。 diff --git "a/doc/20170422/\351\273\230\350\256\244\345\217\202\346\225\260.txt" "b/doc/20170422/\351\273\230\350\256\244\345\217\202\346\225\260.txt" deleted file mode 100644 index 0164c18..0000000 --- "a/doc/20170422/\351\273\230\350\256\244\345\217\202\346\225\260.txt" +++ /dev/null @@ -1,24 +0,0 @@ -新的power(x,n)函数定义没有问题,但是,旧的调用代码失败了,原因是我们增加了一个参数,导致旧的代码因为缺少一个参数而无法正常 -调用。 -power(5) -Traceback (most recent call last): - File "", line 1, in -TypeError: power() missing 1 required positional argument: 'n' - -Python的错误信息很明确:调用函数power()缺少了一个位置参数n. - -这个时候,默认参数就排上用场了,由于我们经常计算x2,所有,完全可以把 -第二参数n的第二个位置参数2 - -所以,定义默认参数要牢记一点:默认参数必须指向不变对象! - -要修改上面的例子,我们可以用None这个不变对象来实现: - -def add_end(L=None): - if L is None: - L = [] - L.append('END') - return L - - - diff --git a/doc/func_call.txt b/doc/func_call.txt deleted file mode 100644 index b37663f..0000000 --- a/doc/func_call.txt +++ /dev/null @@ -1 +0,0 @@ -` diff --git "a/doc/\344\275\277\347\224\250list\345\222\214tuple.txt" "b/doc/\344\275\277\347\224\250list\345\222\214tuple.txt" deleted file mode 100644 index b35e97d..0000000 --- "a/doc/\344\275\277\347\224\250list\345\222\214tuple.txt" +++ /dev/null @@ -1,73 +0,0 @@ -Pythom的内置一组数据类型是列表 -list , list是一种有序的集合。 -可以随时添加和删除其中的元素。 - -classmates = ['Michael','Bob','Tracy'] - -读取列表的值 - -classmates[0] -classmate[2] - - -classmates[3] -IndexError: list index out of range -记得最后一个元素的索引是len(classmates) - 1. -取最后的一个元素的写法classmates[-1] - -以此类推, 倒数第二classmates[-2], 倒数第三.calssmates[-3], -倒数第四,classmates[-4] out of range ->>> del classmates; ->>> classmates='test' ->>> classmates -'test' ->>> type(classmates) - ->>> classmates=[] ->>> type(classmates) - ->>> -list是一个可变的有序表,所以, 可以往list中追加元素到末尾: - -classmates.append('Adam') - -> classmates = ['Michael', 'Bob', 'Tracy'] ->>> classmates.append('Adam') ->>> classmates; -['Michael', 'Bob', 'Tracy', 'Adam'] ->>> len(classmates) -4 - -也可以把元素插入到指定的位置,比如索引号为1的位置1 ->> classmates.insert(1, 'Jack') ->>> classmates -['Michael', 'Jack', 'Bob', 'Tracy', 'Adam'] -要删除list末尾的元素, 用pop()方法。 - - classmates.pop() -'Adam' ->>> classmates -['Michael', 'Jack', 'Bob', 'Tracy'] ->>> : -要删除指定位置的元素, 用pop(i)方法, 其中i是索引位置。 - ->>> classmates.pop(0) -'Michael' ->>> classmates -['Jack', 'Bob', 'Tracy'] -把列表第一个元素删除掉。 - -list里面的元素的数据类型也可以不同,比如。 -L = ['Apple',123,True] - ->>> L = ['Apple',123,True] ->>> L -['Apple', 123, True] - -list 元素也可以是另一个list,比如: - -s = ['python','java',['asp','php'],'scheme'] -len(s) - s = ['pyrhon','java',['asp','php'],'scheme'] ->>> len(s) -4 diff --git "a/doc/\344\275\277\347\224\250\345\205\203\347\273\204.txt" "b/doc/\344\275\277\347\224\250\345\205\203\347\273\204.txt" deleted file mode 100644 index 78b190c..0000000 --- "a/doc/\344\275\277\347\224\250\345\205\203\347\273\204.txt" +++ /dev/null @@ -1,5 +0,0 @@ -tuple -另一种有序列表叫元组:tuple. tuple和list非常类似,但是tuple一旦初始化就不呢修改, -比如同样是列出同学的名字。 - -classmates = ('Michael', 'Bob','Tracy') diff --git "a/doc/\345\210\227\350\241\250\344\270\216\346\225\260\345\255\227\347\232\204\346\257\224\350\276\203.txt" "b/doc/\345\210\227\350\241\250\344\270\216\346\225\260\345\255\227\347\232\204\346\257\224\350\276\203.txt" deleted file mode 100644 index 0f72523..0000000 --- "a/doc/\345\210\227\350\241\250\344\270\216\346\225\260\345\255\227\347\232\204\346\257\224\350\276\203.txt" +++ /dev/null @@ -1,17 +0,0 @@ -请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。 - -和list比较,dict有以下几个特点: - -查找和插入的速度极快,不会随着key的增加而增加; -需要占用大量的内存,内存浪费多。 -而list相反: - -查找和插入的时间随着元素的增加而增加; -占用空间小,浪费内存很少。 -所以,dict是用空间来换取时间的一种方法。 - -dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象。 - -这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。 - -要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key: diff --git "a/doc/\345\255\227\345\205\270\347\232\204\344\275\277\347\224\250.txt" "b/doc/\345\255\227\345\205\270\347\232\204\344\275\277\347\224\250.txt" deleted file mode 100644 index 8493ed7..0000000 --- "a/doc/\345\255\227\345\205\270\347\232\204\344\275\277\347\224\250.txt" +++ /dev/null @@ -1,24 +0,0 @@ -dict -Python内置了字典, -dict的支持,dict全称为dictionary,在其他语言中也称为map, -使用键-值(key-value)存储,具有极快的查找速度。 -举个例子, 假设要根据同学的名字查找对应的成绩,如果用list实现,需要两个list: -name = ['Michael','Bob','Tracy'] -scores = [95,75,85] - -d = {'Michael':95,'Bob':75, 'Tracy':85} -d['Michael'] - -为什么dict查找速度这么快?因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。 - -第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字,无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。 - -dict就是第二种实现方式,给定一个名字,比如'Michael',dict在内部就可以直接计算出Michael对应的存放成绩的“页码”,也就是95这个数字存放的内存地址,直接取出来,所以速度非常快。 - -你可以猜到,这种key-value存储方式,在放进去的时候,必须根据key算出value的存放位置,这样,取的时候才能根据key直接拿到value。 - -把数据放入dict的方法,除了初始化时指定外,还可以通过key放入 - -由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉: - - diff --git a/hello.py b/hello.py new file mode 100644 index 0000000..5e6a007 --- /dev/null +++ b/hello.py @@ -0,0 +1,2 @@ +from flask import Flask +app = Flask(__name__) diff --git a/kh_api/post_http/post.py b/kh_api/post_http/post.py deleted file mode 100644 index a110eed..0000000 --- a/kh_api/post_http/post.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -#coding=utf8 - -import httplib, urllib - -httpClient = None -try: - params = urllib.urlencode({'name': 'Maximus', 'addr': "GZ"}) - headers = {"Content-type": "application/x-www-form-urlencoded" - , "Accept": "text/plain"} - - httpClient = httplib.HTTPConnection("", 80, timeout=30) - httpClient.request("POST", "/test0.html", params, headers) - - response = httpClient.getresponse() - print response.status - print response.reason - print response.read() - print response.getheaders() #获取头信息 -except Exception, e: - print e -finally: - if httpClient: - httpClient.close() diff --git a/kh_api/post_http/pythondb.py b/kh_api/post_http/pythondb.py deleted file mode 100644 index 49ab777..0000000 --- a/kh_api/post_http/pythondb.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/env python -# -*- coding:utf-8 -*- -from sqlalchemy import Column, String, create_engine -from sqlalchemy.orm import sessionmaker -from sqlalchemy.ext.declarative import declarative_base - -# 创建对象的基类: -Base = declarative_base() - -# 定义User对象: -class User(Base): - # 表的名字: - __tablename__ = 'user' - - # 表的结构: - id = Column(String(20), primary_key=True) - name = Column(String(20)) - -# 初始化数据库连接: -engine = create_engine('mysql+mysqlconnector://root:root@localhost:3306/test') -# 创建DBSession类型: -DBSession = sessionmaker(bind=engine) diff --git a/kh_api/selectCourse.py b/kh_api/selectCourse.py deleted file mode 100644 index 9c3295f..0000000 --- a/kh_api/selectCourse.py +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/env python3 -# -*- coding:utf-8 -*- -from urllib import request -#这是python3的模块 如果有错误,请使用python3运行 -with request.urlopen('http://kehai.com/site/ptcourse/ignore/ignore/ignore/ignore/ignore/ignore/100/1/ignore/Topic/ignore/selectCourse.do') as f: - data = f.read() - print('Status:', f.status, f.reason) - for k, v in f.getheaders(): - print('%s: %s' % (k, v)) - print('Data:', data.decode('utf-8')) diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 0000000..e811ee6 --- /dev/null +++ b/venv/bin/activate @@ -0,0 +1,78 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + unset -f pydoc >/dev/null 2>&1 + + # reset old environment variables + # ! [ -z ${VAR+_} ] returns true if VAR is declared at all + if ! [ -z "${_OLD_VIRTUAL_PATH+_}" ] ; then + PATH="$_OLD_VIRTUAL_PATH" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if ! [ -z "${_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-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null + fi + + if ! [ -z "${_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/flasky/venv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +if ! [ -z "${PYTHONHOME+_}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then + _OLD_VIRTUAL_PS1="$PS1" + if [ "x" != x ] ; then + PS1="$PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`) $PS1" + fi + export PS1 +fi + +# Make sure to unalias pydoc if it's already there +alias pydoc 2>/dev/null >/dev/null && unalias pydoc + +pydoc () { + python -m pydoc "$@" +} + +# 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-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null +fi diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 0000000..4fd1bf5 --- /dev/null +++ b/venv/bin/activate.csh @@ -0,0 +1,36 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . + +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 && unalias pydoc' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/root/flasky/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + + +if ("" != "") then + set env_name = "" +else + set env_name = `basename "$VIRTUAL_ENV"` +endif + +# Could be in a non-interactive environment, +# in which case, $prompt is undefined and we wouldn't +# care about the prompt anyway. +if ( $?prompt ) then + set _OLD_VIRTUAL_PROMPT="$prompt" + set prompt = "[$env_name] $prompt" +endif + +unset env_name + +alias pydoc python -m pydoc + +rehash + diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 0000000..ac45543 --- /dev/null +++ b/venv/bin/activate.fish @@ -0,0 +1,76 @@ +# This file must be used using `. bin/activate.fish` *within a running fish ( http://fishshell.com ) session*. +# Do not run it directly. + +function deactivate -d 'Exit virtualenv mode and return to the normal environment.' + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + # Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`. + set -l fish_function_path + + # Erase virtualenv's `fish_prompt` and restore the original. + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + end + + set -e VIRTUAL_ENV + + if test "$argv[1]" != 'nondestructive' + # Self-destruct! + functions -e pydoc + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/root/flasky/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 + +function pydoc + python -m pydoc $argv +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # Copy the current `fish_prompt` function as `_old_fish_prompt`. + functions -c fish_prompt _old_fish_prompt + + function fish_prompt + # Save the current $status, for fish_prompts that display it. + set -l old_status $status + + # Prompt override provided? + # If not, just prepend the environment name. + if test -n "" + printf '%s%s' "" (set_color normal) + else + printf '%s(%s) ' (set_color normal) (basename "$VIRTUAL_ENV") + end + + # Restore the original $status + echo "exit $old_status" | source + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/venv/bin/activate_this.py b/venv/bin/activate_this.py new file mode 100644 index 0000000..f18193b --- /dev/null +++ b/venv/bin/activate_this.py @@ -0,0 +1,34 @@ +"""By using execfile(this_file, dict(__file__=this_file)) you will +activate this virtualenv environment. + +This can be used when you must use an existing Python interpreter, not +the virtualenv bin/python +""" + +try: + __file__ +except NameError: + raise AssertionError( + "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") +import sys +import os + +old_os_path = os.environ.get('PATH', '') +os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path +base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +if sys.platform == 'win32': + site_packages = os.path.join(base, 'Lib', 'site-packages') +else: + site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') +prev_sys_path = list(sys.path) +import site +site.addsitedir(site_packages) +sys.real_prefix = sys.prefix +sys.prefix = base +# Move the added items to the front of the path: +new_sys_path = [] +for item in list(sys.path): + if item not in prev_sys_path: + new_sys_path.append(item) + sys.path.remove(item) +sys.path[:0] = new_sys_path diff --git a/venv/bin/easy_install b/venv/bin/easy_install new file mode 100755 index 0000000..fd68650 --- /dev/null +++ b/venv/bin/easy_install @@ -0,0 +1,11 @@ +#!/root/flasky/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from setuptools.command.easy_install import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/easy_install-2.7 b/venv/bin/easy_install-2.7 new file mode 100755 index 0000000..fd68650 --- /dev/null +++ b/venv/bin/easy_install-2.7 @@ -0,0 +1,11 @@ +#!/root/flasky/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from setuptools.command.easy_install import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/flask b/venv/bin/flask new file mode 100755 index 0000000..245327e --- /dev/null +++ b/venv/bin/flask @@ -0,0 +1,11 @@ +#!/root/flasky/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from flask.cli import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip b/venv/bin/pip new file mode 100755 index 0000000..ea64543 --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,11 @@ +#!/root/flasky/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from pip import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip2 b/venv/bin/pip2 new file mode 100755 index 0000000..ea64543 --- /dev/null +++ b/venv/bin/pip2 @@ -0,0 +1,11 @@ +#!/root/flasky/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from pip import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip2.7 b/venv/bin/pip2.7 new file mode 100755 index 0000000..ea64543 --- /dev/null +++ b/venv/bin/pip2.7 @@ -0,0 +1,11 @@ +#!/root/flasky/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from pip import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 100755 index 0000000..7e7d6dd Binary files /dev/null and b/venv/bin/python differ diff --git a/venv/bin/python-config b/venv/bin/python-config new file mode 100755 index 0000000..d24bd0f --- /dev/null +++ b/venv/bin/python-config @@ -0,0 +1,78 @@ +#!/root/flasky/venv/bin/python + +import sys +import getopt +import sysconfig + +valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', + 'ldflags', 'help'] + +if sys.version_info >= (3, 2): + valid_opts.insert(-1, 'extension-suffix') + valid_opts.append('abiflags') +if sys.version_info >= (3, 3): + valid_opts.append('configdir') + + +def exit_with_usage(code=1): + sys.stderr.write("Usage: {0} [{1}]\n".format( + sys.argv[0], '|'.join('--'+opt for opt in valid_opts))) + sys.exit(code) + +try: + opts, args = getopt.getopt(sys.argv[1:], '', valid_opts) +except getopt.error: + exit_with_usage() + +if not opts: + exit_with_usage() + +pyver = sysconfig.get_config_var('VERSION') +getvar = sysconfig.get_config_var + +opt_flags = [flag for (flag, val) in opts] + +if '--help' in opt_flags: + exit_with_usage(code=0) + +for opt in opt_flags: + if opt == '--prefix': + print(sysconfig.get_config_var('prefix')) + + elif opt == '--exec-prefix': + print(sysconfig.get_config_var('exec_prefix')) + + elif opt in ('--includes', '--cflags'): + flags = ['-I' + sysconfig.get_path('include'), + '-I' + sysconfig.get_path('platinclude')] + if opt == '--cflags': + flags.extend(getvar('CFLAGS').split()) + print(' '.join(flags)) + + elif opt in ('--libs', '--ldflags'): + abiflags = getattr(sys, 'abiflags', '') + libs = ['-lpython' + pyver + abiflags] + libs += getvar('LIBS').split() + libs += getvar('SYSLIBS').split() + # add the prefix/lib/pythonX.Y/config dir, but only if there is no + # shared library in prefix/lib/. + if opt == '--ldflags': + if not getvar('Py_ENABLE_SHARED'): + libs.insert(0, '-L' + getvar('LIBPL')) + if not getvar('PYTHONFRAMEWORK'): + libs.extend(getvar('LINKFORSHARED').split()) + print(' '.join(libs)) + + elif opt == '--extension-suffix': + ext_suffix = sysconfig.get_config_var('EXT_SUFFIX') + if ext_suffix is None: + ext_suffix = sysconfig.get_config_var('SO') + print(ext_suffix) + + elif opt == '--abiflags': + if not getattr(sys, 'abiflags', None): + exit_with_usage() + print(sys.abiflags) + + elif opt == '--configdir': + print(sysconfig.get_config_var('LIBPL')) diff --git a/venv/bin/python2 b/venv/bin/python2 new file mode 120000 index 0000000..d8654aa --- /dev/null +++ b/venv/bin/python2 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/venv/bin/python2.7 b/venv/bin/python2.7 new file mode 120000 index 0000000..d8654aa --- /dev/null +++ b/venv/bin/python2.7 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/venv/bin/wheel b/venv/bin/wheel new file mode 100755 index 0000000..305d11f --- /dev/null +++ b/venv/bin/wheel @@ -0,0 +1,11 @@ +#!/root/flasky/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from wheel.tool import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/include/python2.7 b/venv/include/python2.7 new file mode 120000 index 0000000..ad4ca80 --- /dev/null +++ b/venv/include/python2.7 @@ -0,0 +1 @@ +/usr/include/python2.7 \ No newline at end of file diff --git a/venv/lib/python2.7/UserDict.py b/venv/lib/python2.7/UserDict.py new file mode 120000 index 0000000..93debdb --- /dev/null +++ b/venv/lib/python2.7/UserDict.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/UserDict.py \ No newline at end of file diff --git a/venv/lib/python2.7/UserDict.pyc b/venv/lib/python2.7/UserDict.pyc new file mode 100644 index 0000000..44db25b Binary files /dev/null and b/venv/lib/python2.7/UserDict.pyc differ diff --git a/venv/lib/python2.7/_abcoll.py b/venv/lib/python2.7/_abcoll.py new file mode 120000 index 0000000..c066ac4 --- /dev/null +++ b/venv/lib/python2.7/_abcoll.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/_abcoll.py \ No newline at end of file diff --git a/venv/lib/python2.7/_abcoll.pyc b/venv/lib/python2.7/_abcoll.pyc new file mode 100644 index 0000000..17e6dab Binary files /dev/null and b/venv/lib/python2.7/_abcoll.pyc differ diff --git a/venv/lib/python2.7/_weakrefset.py b/venv/lib/python2.7/_weakrefset.py new file mode 120000 index 0000000..d8f40d9 --- /dev/null +++ b/venv/lib/python2.7/_weakrefset.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/_weakrefset.py \ No newline at end of file diff --git a/venv/lib/python2.7/_weakrefset.pyc b/venv/lib/python2.7/_weakrefset.pyc new file mode 100644 index 0000000..945d7fa Binary files /dev/null and b/venv/lib/python2.7/_weakrefset.pyc differ diff --git a/venv/lib/python2.7/abc.py b/venv/lib/python2.7/abc.py new file mode 120000 index 0000000..a00e405 --- /dev/null +++ b/venv/lib/python2.7/abc.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/abc.py \ No newline at end of file diff --git a/venv/lib/python2.7/abc.pyc b/venv/lib/python2.7/abc.pyc new file mode 100644 index 0000000..57128f6 Binary files /dev/null and b/venv/lib/python2.7/abc.pyc differ diff --git a/venv/lib/python2.7/codecs.py b/venv/lib/python2.7/codecs.py new file mode 120000 index 0000000..85eb651 --- /dev/null +++ b/venv/lib/python2.7/codecs.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/codecs.py \ No newline at end of file diff --git a/venv/lib/python2.7/codecs.pyc b/venv/lib/python2.7/codecs.pyc new file mode 100644 index 0000000..cc5292f Binary files /dev/null and b/venv/lib/python2.7/codecs.pyc differ diff --git a/venv/lib/python2.7/config b/venv/lib/python2.7/config new file mode 120000 index 0000000..0a73e11 --- /dev/null +++ b/venv/lib/python2.7/config @@ -0,0 +1 @@ +/usr/lib64/python2.7/config \ No newline at end of file diff --git a/venv/lib/python2.7/copy_reg.py b/venv/lib/python2.7/copy_reg.py new file mode 120000 index 0000000..16d82c6 --- /dev/null +++ b/venv/lib/python2.7/copy_reg.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/copy_reg.py \ No newline at end of file diff --git a/venv/lib/python2.7/copy_reg.pyc b/venv/lib/python2.7/copy_reg.pyc new file mode 100644 index 0000000..d38cf5a Binary files /dev/null and b/venv/lib/python2.7/copy_reg.pyc differ diff --git a/venv/lib/python2.7/distutils/__init__.py b/venv/lib/python2.7/distutils/__init__.py new file mode 100644 index 0000000..29fc1da --- /dev/null +++ b/venv/lib/python2.7/distutils/__init__.py @@ -0,0 +1,101 @@ +import os +import sys +import warnings +import imp +import opcode # opcode is not a virtualenv module, so we can use it to find the stdlib + # Important! To work on pypy, this must be a module that resides in the + # lib-python/modified-x.y.z directory + +dirname = os.path.dirname + +distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils') +if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)): + warnings.warn( + "The virtualenv distutils package at %s appears to be in the same location as the system distutils?") +else: + __path__.insert(0, distutils_path) + real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ('', '', imp.PKG_DIRECTORY)) + # Copy the relevant attributes + try: + __revision__ = real_distutils.__revision__ + except AttributeError: + pass + __version__ = real_distutils.__version__ + +from distutils import dist, sysconfig + +try: + basestring +except NameError: + basestring = str + +## patch build_ext (distutils doesn't know how to get the libs directory +## path on windows - it hardcodes the paths around the patched sys.prefix) + +if sys.platform == 'win32': + from distutils.command.build_ext import build_ext as old_build_ext + class build_ext(old_build_ext): + def finalize_options (self): + if self.library_dirs is None: + self.library_dirs = [] + elif isinstance(self.library_dirs, basestring): + self.library_dirs = self.library_dirs.split(os.pathsep) + + self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs")) + old_build_ext.finalize_options(self) + + from distutils.command import build_ext as build_ext_module + build_ext_module.build_ext = build_ext + +## distutils.dist patches: + +old_find_config_files = dist.Distribution.find_config_files +def find_config_files(self): + found = old_find_config_files(self) + system_distutils = os.path.join(distutils_path, 'distutils.cfg') + #if os.path.exists(system_distutils): + # found.insert(0, system_distutils) + # What to call the per-user config file + if os.name == 'posix': + user_filename = ".pydistutils.cfg" + else: + user_filename = "pydistutils.cfg" + user_filename = os.path.join(sys.prefix, user_filename) + if os.path.isfile(user_filename): + for item in list(found): + if item.endswith('pydistutils.cfg'): + found.remove(item) + found.append(user_filename) + return found +dist.Distribution.find_config_files = find_config_files + +## distutils.sysconfig patches: + +old_get_python_inc = sysconfig.get_python_inc +def sysconfig_get_python_inc(plat_specific=0, prefix=None): + if prefix is None: + prefix = sys.real_prefix + return old_get_python_inc(plat_specific, prefix) +sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__ +sysconfig.get_python_inc = sysconfig_get_python_inc + +old_get_python_lib = sysconfig.get_python_lib +def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None): + if standard_lib and prefix is None: + prefix = sys.real_prefix + return old_get_python_lib(plat_specific, standard_lib, prefix) +sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__ +sysconfig.get_python_lib = sysconfig_get_python_lib + +old_get_config_vars = sysconfig.get_config_vars +def sysconfig_get_config_vars(*args): + real_vars = old_get_config_vars(*args) + if sys.platform == 'win32': + lib_dir = os.path.join(sys.real_prefix, "libs") + if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars: + real_vars['LIBDIR'] = lib_dir # asked for all + elif isinstance(real_vars, list) and 'LIBDIR' in args: + real_vars = real_vars + [lib_dir] # asked for list + return real_vars +sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__ +sysconfig.get_config_vars = sysconfig_get_config_vars diff --git a/venv/lib/python2.7/distutils/__init__.pyc b/venv/lib/python2.7/distutils/__init__.pyc new file mode 100644 index 0000000..75b749f Binary files /dev/null and b/venv/lib/python2.7/distutils/__init__.pyc differ diff --git a/venv/lib/python2.7/distutils/distutils.cfg b/venv/lib/python2.7/distutils/distutils.cfg new file mode 100644 index 0000000..1af230e --- /dev/null +++ b/venv/lib/python2.7/distutils/distutils.cfg @@ -0,0 +1,6 @@ +# This is a config file local to this virtualenv installation +# You may include options that will be used by all distutils commands, +# and by easy_install. For instance: +# +# [easy_install] +# find_links = http://mylocalsite diff --git a/venv/lib/python2.7/encodings b/venv/lib/python2.7/encodings new file mode 120000 index 0000000..c63e155 --- /dev/null +++ b/venv/lib/python2.7/encodings @@ -0,0 +1 @@ +/usr/lib64/python2.7/encodings \ No newline at end of file diff --git a/venv/lib/python2.7/fnmatch.py b/venv/lib/python2.7/fnmatch.py new file mode 120000 index 0000000..39e4a82 --- /dev/null +++ b/venv/lib/python2.7/fnmatch.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/fnmatch.py \ No newline at end of file diff --git a/venv/lib/python2.7/fnmatch.pyc b/venv/lib/python2.7/fnmatch.pyc new file mode 100644 index 0000000..88cfa00 Binary files /dev/null and b/venv/lib/python2.7/fnmatch.pyc differ diff --git a/venv/lib/python2.7/genericpath.py b/venv/lib/python2.7/genericpath.py new file mode 120000 index 0000000..bb618e8 --- /dev/null +++ b/venv/lib/python2.7/genericpath.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/genericpath.py \ No newline at end of file diff --git a/venv/lib/python2.7/genericpath.pyc b/venv/lib/python2.7/genericpath.pyc new file mode 100644 index 0000000..9b25a79 Binary files /dev/null and b/venv/lib/python2.7/genericpath.pyc differ diff --git a/venv/lib/python2.7/lib-dynload b/venv/lib/python2.7/lib-dynload new file mode 120000 index 0000000..2cdff3a --- /dev/null +++ b/venv/lib/python2.7/lib-dynload @@ -0,0 +1 @@ +/usr/lib64/python2.7/lib-dynload \ No newline at end of file diff --git a/venv/lib/python2.7/linecache.py b/venv/lib/python2.7/linecache.py new file mode 120000 index 0000000..6b94f51 --- /dev/null +++ b/venv/lib/python2.7/linecache.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/linecache.py \ No newline at end of file diff --git a/venv/lib/python2.7/linecache.pyc b/venv/lib/python2.7/linecache.pyc new file mode 100644 index 0000000..a923ad8 Binary files /dev/null and b/venv/lib/python2.7/linecache.pyc differ diff --git a/venv/lib/python2.7/locale.py b/venv/lib/python2.7/locale.py new file mode 120000 index 0000000..f1209dc --- /dev/null +++ b/venv/lib/python2.7/locale.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/locale.py \ No newline at end of file diff --git a/venv/lib/python2.7/locale.pyc b/venv/lib/python2.7/locale.pyc new file mode 100644 index 0000000..f96e0d5 Binary files /dev/null and b/venv/lib/python2.7/locale.pyc differ diff --git a/venv/lib/python2.7/no-global-site-packages.txt b/venv/lib/python2.7/no-global-site-packages.txt new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python2.7/ntpath.py b/venv/lib/python2.7/ntpath.py new file mode 120000 index 0000000..758916a --- /dev/null +++ b/venv/lib/python2.7/ntpath.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/ntpath.py \ No newline at end of file diff --git a/venv/lib/python2.7/orig-prefix.txt b/venv/lib/python2.7/orig-prefix.txt new file mode 100644 index 0000000..e25db58 --- /dev/null +++ b/venv/lib/python2.7/orig-prefix.txt @@ -0,0 +1 @@ +/usr \ No newline at end of file diff --git a/venv/lib/python2.7/os.py b/venv/lib/python2.7/os.py new file mode 120000 index 0000000..201950a --- /dev/null +++ b/venv/lib/python2.7/os.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/os.py \ No newline at end of file diff --git a/venv/lib/python2.7/os.pyc b/venv/lib/python2.7/os.pyc new file mode 100644 index 0000000..a932338 Binary files /dev/null and b/venv/lib/python2.7/os.pyc differ diff --git a/venv/lib/python2.7/posixpath.py b/venv/lib/python2.7/posixpath.py new file mode 120000 index 0000000..eb6aa93 --- /dev/null +++ b/venv/lib/python2.7/posixpath.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/posixpath.py \ No newline at end of file diff --git a/venv/lib/python2.7/posixpath.pyc b/venv/lib/python2.7/posixpath.pyc new file mode 100644 index 0000000..f2b2f07 Binary files /dev/null and b/venv/lib/python2.7/posixpath.pyc differ diff --git a/venv/lib/python2.7/re.py b/venv/lib/python2.7/re.py new file mode 120000 index 0000000..b16e3bf --- /dev/null +++ b/venv/lib/python2.7/re.py @@ -0,0 +1 @@ +/usr/lib64/python2.7/re.py \ No newline at end of file diff --git a/venv/lib/python2.7/re.pyc b/venv/lib/python2.7/re.pyc new file mode 100644 index 0000000..b506efd Binary files /dev/null and b/venv/lib/python2.7/re.pyc differ diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..239dbda --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/DESCRIPTION.rst @@ -0,0 +1,46 @@ +Flask +----- + +Flask is a microframework for Python based on Werkzeug, Jinja 2 and good +intentions. And before you ask: It's BSD licensed! + +Flask is Fun +```````````` + +Save in a hello.py: + +.. code:: python + + from flask import Flask + app = Flask(__name__) + + @app.route("/") + def hello(): + return "Hello World!" + + if __name__ == "__main__": + app.run() + +And Easy to Setup +````````````````` + +And run it: + +.. code:: bash + + $ pip install Flask + $ python hello.py + * Running on http://localhost:5000/ + + Ready for production? `Read this first `. + +Links +````` + +* `website `_ +* `documentation `_ +* `development version + `_ + + + diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..a7da10e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/LICENSE.txt @@ -0,0 +1,33 @@ +Copyright (c) 2015 by Armin Ronacher and contributors. See AUTHORS +for more details. + +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. + +* 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 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 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/METADATA b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/METADATA new file mode 100644 index 0000000..56a5a10 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/METADATA @@ -0,0 +1,75 @@ +Metadata-Version: 2.0 +Name: Flask +Version: 0.12.1 +Summary: A microframework based on Werkzeug, Jinja2 and good intentions +Home-page: http://github.com/pallets/flask/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Platform: any +Classifier: Development Status :: 4 - Beta +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: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Dist: Jinja2 (>=2.4) +Requires-Dist: Werkzeug (>=0.7) +Requires-Dist: click (>=2.0) +Requires-Dist: itsdangerous (>=0.21) + +Flask +----- + +Flask is a microframework for Python based on Werkzeug, Jinja 2 and good +intentions. And before you ask: It's BSD licensed! + +Flask is Fun +```````````` + +Save in a hello.py: + +.. code:: python + + from flask import Flask + app = Flask(__name__) + + @app.route("/") + def hello(): + return "Hello World!" + + if __name__ == "__main__": + app.run() + +And Easy to Setup +````````````````` + +And run it: + +.. code:: bash + + $ pip install Flask + $ python hello.py + * Running on http://localhost:5000/ + + Ready for production? `Read this first `. + +Links +````` + +* `website `_ +* `documentation `_ +* `development version + `_ + + + diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/RECORD b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/RECORD new file mode 100644 index 0000000..e6158e4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/RECORD @@ -0,0 +1,52 @@ +Flask-0.12.1.dist-info/DESCRIPTION.rst,sha256=DmJm8IBlBjl3wkm0Ly23jYvWbvK_mCuE5oUseYCijbI,810 +Flask-0.12.1.dist-info/LICENSE.txt,sha256=hLgKluMRHSnxG-L0EmrqjmKgG5cHlff6pIh3rCNINeI,1582 +Flask-0.12.1.dist-info/METADATA,sha256=SG7efIuuoa51GNPZ0gD4PnB-X-US_yk7xlKBkoMAnAI,1948 +Flask-0.12.1.dist-info/RECORD,, +Flask-0.12.1.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 +Flask-0.12.1.dist-info/entry_points.txt,sha256=jzk2Wy2h30uEcqqzd4CVnlzsMXB-vaD5GXjuPMXmTmI,60 +Flask-0.12.1.dist-info/metadata.json,sha256=6nWCwJZ8_KE2QOFkfrcgOc7vfLsJVJie2GP6eFRdQG0,1389 +Flask-0.12.1.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 +flask/__init__.py,sha256=PyjiUdcIkBrx6NAW441uD4d2lsjHgGPyh96TBRvzZ0w,1673 +flask/__main__.py,sha256=cldbNi5zpjE68XzIWI8uYHNWwBHHVJmwtlXWk6P4CO4,291 +flask/_compat.py,sha256=VlfjUuLjufsTHJIjr_ZsnnOesSbAXIslBBgRe5tfOok,2802 +flask/app.py,sha256=6DPjtb5jUJWgL5fXksG5boA49EB3l-k9pWyftitbNNk,83169 +flask/blueprints.py,sha256=6HVasMcPcaq7tk36kCrgX4bnhTkky4G5WIWCyyJL8HY,16872 +flask/cli.py,sha256=2NXEdCOu5-4ymklxX4Lf6bjb-89I4VHYeP6xScR3i8E,18328 +flask/config.py,sha256=Ym5Jenyu6zAZ1fdVLeKekY9-EsKmq8183qnRgauwCMY,9905 +flask/ctx.py,sha256=UPA0YwoIlHP0txOGanC9lQLSGv6eCqV5Fmw2cVJRmgQ,14739 +flask/debughelpers.py,sha256=z-uQavKIymOZl0WQDLXsnacA00ERIlCx3S3Tnb_OYsE,6024 +flask/exthook.py,sha256=SvXs5jwpcOjogwJ7SNquiWTxowoN1-MHFoqAejWnk2o,5762 +flask/globals.py,sha256=I3m_4RssLhWW1R11zuEI8oFryHUHX3NQwjMkGXOZzg8,1645 +flask/helpers.py,sha256=LK4CQkN0LViGYH4FP5GLsS74SwedsHz4zO5awHOtzaQ,38449 +flask/json.py,sha256=1zPM-NPLiWoOfGd0P14FxnEkeKtjtUZxMC9pyYyDBYI,9183 +flask/logging.py,sha256=UG-77jPkRClk9w1B-_ArjjXPuj9AmZz9mG0IRGvptW0,2751 +flask/sessions.py,sha256=QBKXVYKJ-HKbx9m6Yb5yan_EPq84a5yevVLgAzNKFQY,14394 +flask/signals.py,sha256=MfZk5qTRj_R_O3aGYlTEnx2g3SvlZncz8Ii73eKK59g,2209 +flask/templating.py,sha256=u7FbN6j56H_q6CrdJJyJ6gZtqaMa0vh1_GP12gEHRQQ,4912 +flask/testing.py,sha256=II8EO_NjOT1LvL8Hh_SdIFL_BdlwVPcB9yot5pbltxE,5630 +flask/views.py,sha256=6OPv7gwu3h14JhqpeeMRWwrxoGHsUr4_nOGSyTRAxAI,5630 +flask/wrappers.py,sha256=1S_5mmuA1Tlx7D9lXV6xMblrg-PdAauNWahe-henMEE,7612 +flask/ext/__init__.py,sha256=UEezCApsG4ZJWqwUnX9YmWcNN4OVENgph_9L05n0eOM,842 +../../../bin/flask,sha256=ZpV1MZhM0LJ868etb4QdG7V3TfoYKtOIZ6IhohT0wNs,224 +Flask-0.12.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask/config.pyc,, +flask/testing.pyc,, +flask/wrappers.pyc,, +flask/views.pyc,, +flask/logging.pyc,, +flask/json.pyc,, +flask/helpers.pyc,, +flask/__main__.pyc,, +flask/blueprints.pyc,, +flask/signals.pyc,, +flask/__init__.pyc,, +flask/exthook.pyc,, +flask/debughelpers.pyc,, +flask/templating.pyc,, +flask/cli.pyc,, +flask/ctx.pyc,, +flask/_compat.pyc,, +flask/app.pyc,, +flask/globals.pyc,, +flask/ext/__init__.pyc,, +flask/sessions.pyc,, diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/WHEEL new file mode 100644 index 0000000..8b6dd1b --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/entry_points.txt b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/entry_points.txt new file mode 100644 index 0000000..14adf18 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/entry_points.txt @@ -0,0 +1,4 @@ + + [console_scripts] + flask=flask.cli:main + \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/metadata.json b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/metadata.json new file mode 100644 index 0000000..e854c06 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "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", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "extensions": {"python.commands": {"wrap_console": {"flask": "flask.cli:main"}}, "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://github.com/pallets/flask/"}}, "python.exports": {"console_scripts": {"flask": "flask.cli:main"}}}, "extras": [], "generator": "bdist_wheel (0.29.0)", "license": "BSD", "metadata_version": "2.0", "name": "Flask", "platform": "any", "run_requires": [{"requires": ["Jinja2 (>=2.4)", "Werkzeug (>=0.7)", "click (>=2.0)", "itsdangerous (>=0.21)"]}], "summary": "A microframework based on Werkzeug, Jinja2 and good intentions", "version": "0.12.1"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/top_level.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-0.12.1.dist-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..4421f04 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/DESCRIPTION.rst @@ -0,0 +1,36 @@ +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 %} + + {% 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: http://en.wikipedia.org/wiki/Sandbox_(computer_security) +.. _Django: http://www.djangoproject.com/ +.. _Jinja2 webpage: http://jinja.pocoo.org/ +.. _documentation: http://jinja.pocoo.org/2/documentation/ + + diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/LICENSE.txt new file mode 100644 index 0000000..10145a2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/LICENSE.txt @@ -0,0 +1,31 @@ +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. diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/METADATA b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/METADATA new file mode 100644 index 0000000..ea69de1 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/METADATA @@ -0,0 +1,65 @@ +Metadata-Version: 2.0 +Name: Jinja2 +Version: 2.9.6 +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 +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: 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 %} + + {% 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: http://en.wikipedia.org/wiki/Sandbox_(computer_security) +.. _Django: http://www.djangoproject.com/ +.. _Jinja2 webpage: http://jinja.pocoo.org/ +.. _documentation: http://jinja.pocoo.org/2/documentation/ + + diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/RECORD b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/RECORD new file mode 100644 index 0000000..024e389 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/RECORD @@ -0,0 +1,59 @@ +jinja2/__init__.py,sha256=Cx_UnJO4i_GqvKQsOu__mvGE_eMJSsBqITa26irtg5A,2565 +jinja2/_compat.py,sha256=xP60CE5Qr8FTYcDE1f54tbZLKGvMwYml4-8T7Q4KG9k,2596 +jinja2/_stringdefs.py,sha256=PYtqTmmWIhjXlFBoH-eE6fJkQvlu7nxUyQ2YlFB97VA,589381 +jinja2/asyncfilters.py,sha256=cTDPvrS8Hp_IkwsZ1m9af_lr5nHysw7uTa5gV0NmZVE,4144 +jinja2/asyncsupport.py,sha256=ZJO1Fdd9R93sDLrk6TZNuMQGgtuDmpTlENNRkLwZF7c,7765 +jinja2/bccache.py,sha256=0xoVw0R9nj3vtzPl9g-zB5BKTLFJ7FFMq2ABbn1IkCI,12793 +jinja2/compiler.py,sha256=lE5owyPwT1cGGZxWyzQtZLW7Uj1g3Vw1oVtBU8Uc_uM,62929 +jinja2/constants.py,sha256=uwwV8ZUhHhacAuz5PTwckfsbqBaqM7aKfyJL7kGX5YQ,1626 +jinja2/debug.py,sha256=UqEbKb4zofBABwvyA77Kr0-5IAQawKqC9t8ZeTIzpGU,12038 +jinja2/defaults.py,sha256=GvVEQqIRvRMCbQF2NZSr0mlEN8lxvGixU5wIIAeRe1A,1323 +jinja2/environment.py,sha256=z91L_efdYs-KNs6DBxQWDyYncOwOqn_0J4M5CfFj0Q8,50848 +jinja2/exceptions.py,sha256=_Rj-NVi98Q6AiEjYQOsP8dEIdu5AlmRHzcSNOPdWix4,4428 +jinja2/ext.py,sha256=9xq8fd_QPBIe4Z7hE1XawB7f1EDHrVZjpb2JiRTiG94,23867 +jinja2/filters.py,sha256=1OYGhyN84yVmFUIOwJNRV_StqTCfPhnRLfJTmWbEe_8,33424 +jinja2/idtracking.py,sha256=HHcCOMsQhCrrjwYAmikKqq_XetXLovCjXAThh9WbRAc,8760 +jinja2/lexer.py,sha256=W4A830e-fj12zRT6rL7H91F4D6xwED5LjR8iMxjWuVQ,28238 +jinja2/loaders.py,sha256=xiTuURKAEObyym0nU8PCIXu_Qp8fn0AJ5oIADUUm-5Q,17382 +jinja2/meta.py,sha256=fmKHxkmZYAOm9QyWWy8EMd6eefAIh234rkBMW2X4ZR8,4340 +jinja2/nodes.py,sha256=4_Ucxbkohtj4BAlpV0w_MpVmIxJNaVXDTBb4EHBA2JI,29392 +jinja2/optimizer.py,sha256=MsdlFACJ0FRdPtjmCAdt7JQ9SGrXFaDNUaslsWQaG3M,1722 +jinja2/parser.py,sha256=3tc82qO1Ovs9och_PjirbAmnWNT77n4wWjIQ8pEVKvU,35465 +jinja2/runtime.py,sha256=axkTQXg2-oc_Cm35NEMDDas3Jbq3ATxNrDOEa5v3wIw,26835 +jinja2/sandbox.py,sha256=Jx4MTxly8KvdkSWyui_kHY1_ZZ0RAQL4ojAy1KDRyK0,16707 +jinja2/tests.py,sha256=iFuUTbUYv7TFffq2aTswCRdIhQ6wyrby1YevChVPqkE,4428 +jinja2/utils.py,sha256=BIFqeXXsCUSjWx6MEwYhY6V4tXzVNs9WRXfB60MA9HY,19941 +jinja2/visitor.py,sha256=JD1H1cANA29JcntFfN5fPyqQxB4bI4wC00BzZa-XHks,3316 +Jinja2-2.9.6.dist-info/DESCRIPTION.rst,sha256=CXIS1UnPSk5_lZBS6Lb8ko-3lqGfjsiUwNBLXCTj2lc,975 +Jinja2-2.9.6.dist-info/entry_points.txt,sha256=NdzVcOrqyNyKDxD09aERj__3bFx2paZhizFDsKmVhiA,72 +Jinja2-2.9.6.dist-info/LICENSE.txt,sha256=JvzUNv3Io51EiWrAPm8d_SXjhJnEjyDYvB3Tvwqqils,1554 +Jinja2-2.9.6.dist-info/METADATA,sha256=53LSXlqC86JTyLSPsDyAOmyV4pXIzzmmZoUXz7ogytA,2172 +Jinja2-2.9.6.dist-info/metadata.json,sha256=vzvX25T4hwMOe1EIOBo9rpfiZerOB_KVLcplGG_qYtE,1394 +Jinja2-2.9.6.dist-info/RECORD,, +Jinja2-2.9.6.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +Jinja2-2.9.6.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 +Jinja2-2.9.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +jinja2/_compat.pyc,, +jinja2/sandbox.pyc,, +jinja2/_stringdefs.pyc,, +jinja2/bccache.pyc,, +jinja2/runtime.pyc,, +jinja2/utils.pyc,, +jinja2/parser.pyc,, +jinja2/debug.pyc,, +jinja2/lexer.pyc,, +jinja2/defaults.pyc,, +jinja2/visitor.pyc,, +jinja2/nodes.pyc,, +jinja2/environment.pyc,, +jinja2/compiler.pyc,, +jinja2/exceptions.pyc,, +jinja2/filters.pyc,, +jinja2/__init__.pyc,, +jinja2/meta.pyc,, +jinja2/loaders.pyc,, +jinja2/ext.pyc,, +jinja2/optimizer.pyc,, +jinja2/constants.pyc,, +jinja2/tests.pyc,, +jinja2/idtracking.pyc,, diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/WHEEL new file mode 100644 index 0000000..9dff69d --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.24.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/entry_points.txt b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/entry_points.txt new file mode 100644 index 0000000..32e6b75 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/entry_points.txt @@ -0,0 +1,4 @@ + + [babel.extractors] + jinja2 = jinja2.ext:babel_extract[i18n] + \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/metadata.json b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/metadata.json new file mode 100644 index 0000000..9bbf942 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/metadata.json @@ -0,0 +1 @@ +{"license": "BSD", "name": "Jinja2", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "A small but fast and easy to use stand-alone template engine written in pure python.", "run_requires": [{"requires": ["Babel (>=0.8)"], "extra": "i18n"}, {"requires": ["MarkupSafe (>=0.23)"]}], "version": "2.9.6", "extensions": {"python.details": {"project_urls": {"Home": "http://jinja.pocoo.org/"}, "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "contacts": [{"role": "author", "email": "armin.ronacher@active-4.com", "name": "Armin Ronacher"}]}, "python.exports": {"babel.extractors": {"jinja2": "jinja2.ext:babel_extract [i18n]"}}}, "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", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "extras": ["i18n"]} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/top_level.txt new file mode 100644 index 0000000..7f7afbf --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.9.6.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..495211b --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/DESCRIPTION.rst @@ -0,0 +1,115 @@ +MarkupSafe +========== + +Implements a unicode subclass that supports HTML strings: + +.. code-block:: python + + >>> from markupsafe import Markup, escape + >>> escape("") + Markup(u'<script>alert(document.cookie);</script>') + >>> tmpl = Markup("%s") + >>> tmpl % "Peter > Lustig" + Markup(u'Peter > Lustig') + +If you want to make an object unicode that is not yet unicode +but don't want to lose the taint information, you can use the +``soft_unicode`` function. (On Python 3 you can also use ``soft_str`` which +is a different name for the same function). + +.. code-block:: python + + >>> from markupsafe import soft_unicode + >>> soft_unicode(42) + u'42' + >>> soft_unicode(Markup('foo')) + Markup(u'foo') + +HTML Representations +-------------------- + +Objects can customize their HTML markup equivalent by overriding +the ``__html__`` function: + +.. code-block:: python + + >>> class Foo(object): + ... def __html__(self): + ... return 'Nice' + ... + >>> escape(Foo()) + Markup(u'Nice') + >>> Markup(Foo()) + Markup(u'Nice') + +Silent Escapes +-------------- + +Since MarkupSafe 0.10 there is now also a separate escape function +called ``escape_silent`` that returns an empty string for ``None`` for +consistency with other systems that return empty strings for ``None`` +when escaping (for instance Pylons' webhelpers). + +If you also want to use this for the escape method of the Markup +object, you can create your own subclass that does that: + +.. code-block:: python + + from markupsafe import Markup, escape_silent as escape + + class SilentMarkup(Markup): + __slots__ = () + + @classmethod + def escape(cls, s): + return cls(escape(s)) + +New-Style String Formatting +--------------------------- + +Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and +3.x are now fully supported. Previously the escape behavior of those +functions was spotty at best. The new implementations operates under the +following algorithm: + +1. if an object has an ``__html_format__`` method it is called as + replacement for ``__format__`` with the format specifier. It either + has to return a string or markup object. +2. if an object has an ``__html__`` method it is called. +3. otherwise the default format system of Python kicks in and the result + is HTML escaped. + +Here is how you can implement your own formatting: + +.. code-block:: python + + class User(object): + + def __init__(self, id, username): + self.id = id + self.username = username + + def __html_format__(self, format_spec): + if format_spec == 'link': + return Markup('{1}').format( + self.id, + self.__html__(), + ) + elif format_spec: + raise ValueError('Invalid format spec') + return self.__html__() + + def __html__(self): + return Markup('{0}').format(self.username) + +And to format that user: + +.. code-block:: python + + >>> user = User(1, 'foo') + >>> Markup('

User: {0:link}').format(user) + Markup(u'

User: foo') + +Markupsafe supports Python 2.6, 2.7 and Python 3.3 and higher. + + diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..5d26938 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/LICENSE.txt @@ -0,0 +1,33 @@ +Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS +for more details. + +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. + +* 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 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 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/METADATA b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/METADATA new file mode 100644 index 0000000..725be08 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/METADATA @@ -0,0 +1,135 @@ +Metadata-Version: 2.0 +Name: MarkupSafe +Version: 1.0 +Summary: Implements a XML/HTML/XHTML Markup safe string for Python +Home-page: http://github.com/pallets/markupsafe +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +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 :: 3 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML + +MarkupSafe +========== + +Implements a unicode subclass that supports HTML strings: + +.. code-block:: python + + >>> from markupsafe import Markup, escape + >>> escape("") + Markup(u'<script>alert(document.cookie);</script>') + >>> tmpl = Markup("%s") + >>> tmpl % "Peter > Lustig" + Markup(u'Peter > Lustig') + +If you want to make an object unicode that is not yet unicode +but don't want to lose the taint information, you can use the +``soft_unicode`` function. (On Python 3 you can also use ``soft_str`` which +is a different name for the same function). + +.. code-block:: python + + >>> from markupsafe import soft_unicode + >>> soft_unicode(42) + u'42' + >>> soft_unicode(Markup('foo')) + Markup(u'foo') + +HTML Representations +-------------------- + +Objects can customize their HTML markup equivalent by overriding +the ``__html__`` function: + +.. code-block:: python + + >>> class Foo(object): + ... def __html__(self): + ... return 'Nice' + ... + >>> escape(Foo()) + Markup(u'Nice') + >>> Markup(Foo()) + Markup(u'Nice') + +Silent Escapes +-------------- + +Since MarkupSafe 0.10 there is now also a separate escape function +called ``escape_silent`` that returns an empty string for ``None`` for +consistency with other systems that return empty strings for ``None`` +when escaping (for instance Pylons' webhelpers). + +If you also want to use this for the escape method of the Markup +object, you can create your own subclass that does that: + +.. code-block:: python + + from markupsafe import Markup, escape_silent as escape + + class SilentMarkup(Markup): + __slots__ = () + + @classmethod + def escape(cls, s): + return cls(escape(s)) + +New-Style String Formatting +--------------------------- + +Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and +3.x are now fully supported. Previously the escape behavior of those +functions was spotty at best. The new implementations operates under the +following algorithm: + +1. if an object has an ``__html_format__`` method it is called as + replacement for ``__format__`` with the format specifier. It either + has to return a string or markup object. +2. if an object has an ``__html__`` method it is called. +3. otherwise the default format system of Python kicks in and the result + is HTML escaped. + +Here is how you can implement your own formatting: + +.. code-block:: python + + class User(object): + + def __init__(self, id, username): + self.id = id + self.username = username + + def __html_format__(self, format_spec): + if format_spec == 'link': + return Markup('{1}').format( + self.id, + self.__html__(), + ) + elif format_spec: + raise ValueError('Invalid format spec') + return self.__html__() + + def __html__(self): + return Markup('{0}').format(self.username) + +And to format that user: + +.. code-block:: python + + >>> user = User(1, 'foo') + >>> Markup('

User: {0:link}').format(user) + Markup(u'

User: foo') + +Markupsafe supports Python 2.6, 2.7 and Python 3.3 and higher. + + diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/RECORD b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/RECORD new file mode 100644 index 0000000..9fe43c3 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/RECORD @@ -0,0 +1,18 @@ +MarkupSafe-1.0.dist-info/DESCRIPTION.rst,sha256=3B3J0YLzzmJQVaWQ_XlVMhGeHA_DvBqysABvul_5fko,3397 +MarkupSafe-1.0.dist-info/LICENSE.txt,sha256=C76IIo_WPSDsCX9k5Y1aCkZRI64TkUChjUBsYLSIJLU,1582 +MarkupSafe-1.0.dist-info/METADATA,sha256=EUwvRzJbtRP3hBMc8Z2TDT44TBDeZdIurbGzIc7FOkg,4182 +MarkupSafe-1.0.dist-info/RECORD,, +MarkupSafe-1.0.dist-info/WHEEL,sha256=LgENoDL_AkiRWbJ7HCJLnTXVvHl9ZtXZ7UZmjmcCeN0,105 +MarkupSafe-1.0.dist-info/metadata.json,sha256=fQYPE0HEQTuDqIQMBMJTqDCbYC1ILBGiHDpEuVVn4rw,924 +MarkupSafe-1.0.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=xtkRdxhzJzgp65wUo1D4DjnazxHU88pPldaAuDekBeY,10697 +markupsafe/_compat.py,sha256=r1HE0CpcAZeb-AiTV9wITR91PeLHn0CzZ_XHkYoozpI,565 +markupsafe/_constants.py,sha256=U_xybFQsyXKCgHSfranJnFzo-z9nn9fuBeSk243sE5Q,4795 +markupsafe/_native.py,sha256=E2Un1ysOf-w45d18YCj8UelT5UP7Vt__IuFPYJ7YRIs,1187 +markupsafe/_speedups.c,sha256=B6Mf6Fn33WqkagfwY7q5ZBSm_vJoHDYxDB0Jp_DP7Jw,5936 +markupsafe/_speedups.so,sha256=_9MhD2shbWZAO24rkgbU7lZoq0hmRB0BSRjxUciIJ9I,28176 +MarkupSafe-1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +markupsafe/_constants.pyc,, +markupsafe/_compat.pyc,, +markupsafe/__init__.pyc,, +markupsafe/_native.pyc,, diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/WHEEL b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/WHEEL new file mode 100644 index 0000000..d15279d --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: false +Tag: cp27-cp27mu-linux_x86_64 + diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/metadata.json b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/metadata.json new file mode 100644 index 0000000..122208e --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/metadata.json @@ -0,0 +1 @@ +{"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 :: 3", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "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://github.com/pallets/markupsafe"}}}, "generator": "bdist_wheel (0.29.0)", "license": "BSD", "metadata_version": "2.0", "name": "MarkupSafe", "summary": "Implements a XML/HTML/XHTML Markup safe string for Python", "version": "1.0"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..3e3abb7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/DESCRIPTION.rst @@ -0,0 +1,54 @@ +Werkzeug +======== + +Werkzeug started as simple collection of various utilities for WSGI +applications and has become one of the most advanced WSGI utility +modules. It includes a powerful debugger, full featured request and +response objects, HTTP utilities to handle entity tags, cache control +headers, HTTP dates, cookie handling, file uploads, a powerful URL +routing system and a bunch of community contributed addon modules. + +Werkzeug is unicode aware and doesn't enforce a specific template +engine, database adapter or anything else. It doesn't even enforce +a specific way of handling requests and leaves all that up to the +developer. It's most useful for end user applications which should work +on as many server environments as possible (such as blogs, wikis, +bulletin boards, etc.). + +Details and example applications are available on the +`Werkzeug website `_. + + +Features +-------- + +- unicode awareness + +- request and response objects + +- various utility functions for dealing with HTTP headers such as + `Accept` and `Cache-Control` headers. + +- thread local objects with proper cleanup at request end + +- an interactive debugger + +- A simple WSGI server with support for threading and forking + with an automatic reloader. + +- a flexible URL routing system with REST support. + +- fully WSGI compatible + + +Development Version +------------------- + +The Werkzeug development version can be installed by cloning the git +repository from `github`_:: + + git clone git@github.com:pallets/werkzeug.git + +.. _github: http://github.com/pallets/werkzeug + + diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..1c2e0b7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/LICENSE.txt @@ -0,0 +1,29 @@ +Copyright (c) 2014 by the Werkzeug Team, see AUTHORS for more details. + +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. diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/METADATA b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/METADATA new file mode 100644 index 0000000..86c5bdd --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/METADATA @@ -0,0 +1,83 @@ +Metadata-Version: 2.0 +Name: Werkzeug +Version: 0.12.1 +Summary: The Swiss Army knife of Python web development +Home-page: http://werkzeug.pocoo.org/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +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: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Provides-Extra: termcolor +Requires-Dist: termcolor; extra == 'termcolor' +Provides-Extra: watchdog +Requires-Dist: watchdog; extra == 'watchdog' + +Werkzeug +======== + +Werkzeug started as simple collection of various utilities for WSGI +applications and has become one of the most advanced WSGI utility +modules. It includes a powerful debugger, full featured request and +response objects, HTTP utilities to handle entity tags, cache control +headers, HTTP dates, cookie handling, file uploads, a powerful URL +routing system and a bunch of community contributed addon modules. + +Werkzeug is unicode aware and doesn't enforce a specific template +engine, database adapter or anything else. It doesn't even enforce +a specific way of handling requests and leaves all that up to the +developer. It's most useful for end user applications which should work +on as many server environments as possible (such as blogs, wikis, +bulletin boards, etc.). + +Details and example applications are available on the +`Werkzeug website `_. + + +Features +-------- + +- unicode awareness + +- request and response objects + +- various utility functions for dealing with HTTP headers such as + `Accept` and `Cache-Control` headers. + +- thread local objects with proper cleanup at request end + +- an interactive debugger + +- A simple WSGI server with support for threading and forking + with an automatic reloader. + +- a flexible URL routing system with REST support. + +- fully WSGI compatible + + +Development Version +------------------- + +The Werkzeug development version can be installed by cloning the git +repository from `github`_:: + + git clone git@github.com:pallets/werkzeug.git + +.. _github: http://github.com/pallets/werkzeug + + diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/RECORD b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/RECORD new file mode 100644 index 0000000..b5044a0 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/RECORD @@ -0,0 +1,95 @@ +werkzeug/posixemulation.py,sha256=xEF2Bxc-vUCPkiu4IbfWVd3LW7DROYAT-ExW6THqyzw,3519 +werkzeug/security.py,sha256=rbd9Q-Xga1NldPzuiVW5czvBGUXkhWARm_lxrT1Tx54,8990 +werkzeug/__init__.py,sha256=xQyZHWJtl_P88xARoyNi4QXv22yiApBfTRHsob__IFs,6864 +werkzeug/testapp.py,sha256=3HQRW1sHZKXuAjCvFMet4KXtQG3loYTFnvn6LWt-4zI,9396 +werkzeug/http.py,sha256=nrk-ASJzcKOuoBEz274TWA8jKt0CQSOBZuP_A0UASTA,36658 +werkzeug/routing.py,sha256=g25wg0GNfff8WcfRlc1ZxTGvz1KbVj09w2S7wxopseQ,66746 +werkzeug/utils.py,sha256=lkybtv_mq35zV1qhelvEcILTzrMUwZ9yon6E8XwapJE,22972 +werkzeug/exceptions.py,sha256=3wp95Hqj9FqV8MdikV99JRcHse_fSMn27V8tgP5Hw2c,20505 +werkzeug/_reloader.py,sha256=NkIXQCTa6b22wWLpXob_jIVUxux8LtAsfWehLkKt0iM,8816 +werkzeug/formparser.py,sha256=DxN53eOCb6i7PxqtldrF2Kv9Mx00BqW297N4t-RxkWE,21241 +werkzeug/_compat.py,sha256=8c4U9o6A_TR9nKCcTbpZNxpqCXcXDVIbFawwKM2s92c,6311 +werkzeug/datastructures.py,sha256=uajnldfkuVXEcE92qW-uo9YUAprO3Yh5dPDQfnUL9eE,89075 +werkzeug/wrappers.py,sha256=wceh1RhvhIZVzKuok3XMQ5jqjYYCEYv5JqKY3Nc_oRY,82986 +werkzeug/test.py,sha256=xnabNSpty66ftZiXHcoZaYFP1E4WUNxydw5Oe8Mjhoo,34795 +werkzeug/urls.py,sha256=fSbI4Gb29_p02Zk21VAZQRN1QdOVY9CNTgpb2rbajNQ,36710 +werkzeug/script.py,sha256=Jh9OAktqjLNc_IBBUatVM7uP5LDcbxaYA8n2ObnS4bo,11666 +werkzeug/useragents.py,sha256=Ck3G977Y0Rzdk9wFcLpL0PyOrONtdK1_d2Zexb78cX4,5640 +werkzeug/local.py,sha256=QdQhWV5L8p1Y1CJ1CDStwxaUs24SuN5aebHwjVD08C8,14553 +werkzeug/serving.py,sha256=bN5nO4zTqzs-QX4rBxbW1LVF5af0c_vCokhZHO4muUE,28961 +werkzeug/filesystem.py,sha256=hHWeWo_gqLMzTRfYt8-7n2wWcWUNTnDyudQDLOBEICE,2175 +werkzeug/wsgi.py,sha256=TjPo5ups3NI1RVVGdMvd3XaceqFtqlMX5X169gWWFrQ,42838 +werkzeug/_internal.py,sha256=sE2JbLnMzN9mRI1iipTYWrFAGEWaZVECqtHAiNEhqUE,13841 +werkzeug/contrib/fixers.py,sha256=gR06T-w71ur-tHQ_31kP_4jpOncPJ4Wc1dOqTvYusr8,10179 +werkzeug/contrib/limiter.py,sha256=iS8-ahPZ-JLRnmfIBzxpm7O_s3lPsiDMVWv7llAIDCI,1334 +werkzeug/contrib/__init__.py,sha256=f7PfttZhbrImqpr5Ezre8CXgwvcGUJK7zWNpO34WWrw,623 +werkzeug/contrib/testtools.py,sha256=G9xN-qeihJlhExrIZMCahvQOIDxdL9NiX874jiiHFMs,2453 +werkzeug/contrib/iterio.py,sha256=RlqDvGhz0RneTpzE8dVc-yWCUv4nkPl1jEc_EDp2fH0,10814 +werkzeug/contrib/cache.py,sha256=nyUUxsS0MTHiFmu-481y9PHd8NvWH5pzCoEX1yA0mHY,30341 +werkzeug/contrib/securecookie.py,sha256=bDsAJmslkwmXjycnPjEjWtfLBvhz0ud4z3k7tdezUVs,12174 +werkzeug/contrib/lint.py,sha256=qZlmqiWJ5tQJOEzLnPmHWA8eUEpcBIWkAb_V2RKJg4o,12558 +werkzeug/contrib/profiler.py,sha256=ISwCWvwVyGpDLRBRpLjo_qUWma6GXYBrTAco4PEQSHY,5151 +werkzeug/contrib/wrappers.py,sha256=v7OYlz7wQtDlS9fey75UiRZ1IkUWqCpzbhsLy4k14Hw,10398 +werkzeug/contrib/atom.py,sha256=qqfJcfIn2RYY-3hO3Oz0aLq9YuNubcPQ_KZcNsDwVJo,15575 +werkzeug/contrib/jsrouting.py,sha256=QTmgeDoKXvNK02KzXgx9lr3cAH6fAzpwF5bBdPNvJPs,8564 +werkzeug/contrib/sessions.py,sha256=39LVNvLbm5JWpbxM79WC2l87MJFbqeISARjwYbkJatw,12577 +werkzeug/debug/console.py,sha256=n3-dsKk1TsjnN-u4ZgmuWCU_HO0qw5IA7ttjhyyMM6I,5607 +werkzeug/debug/repr.py,sha256=bKqstDYGfECpeLerd48s_hxuqK4b6UWnjMu3d_DHO8I,9340 +werkzeug/debug/__init__.py,sha256=GTsOsjE3PqUAlsUVm2Mgc_KWA2kjjSsUz0JsM7Qu41w,17266 +werkzeug/debug/tbtools.py,sha256=rBudXCmkVdAKIcdhxANxgf09g6kQjJWW9_5bjSpr4OY,18451 +werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191 +werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818 +werkzeug/debug/shared/debugger.js,sha256=PKPVYuyO4SX1hkqLOwCLvmIEO5154WatFYaXE-zIfKI,6264 +werkzeug/debug/shared/style.css,sha256=IEO0PC2pWmh2aEyGCaN--txuWsRCliuhlbEhPDFwh0A,6270 +werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507 +werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673 +werkzeug/debug/shared/jquery.js,sha256=7LkWEzqTdpEfELxcZZlS6wAx5Ff13zZ83lYO2_ujj7g,95957 +werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220 +werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200 +Werkzeug-0.12.1.dist-info/DESCRIPTION.rst,sha256=z9r9xqJ0fYSAn1Tz7KRBdFGDerL2y4pHWSW_72pUgTc,1591 +Werkzeug-0.12.1.dist-info/metadata.json,sha256=gzIVhjk_QMpO2SldxIcRtgkXI3U-x92yMDpyuMy8-WM,1276 +Werkzeug-0.12.1.dist-info/RECORD,, +Werkzeug-0.12.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +Werkzeug-0.12.1.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110 +Werkzeug-0.12.1.dist-info/LICENSE.txt,sha256=F84h8-PZAuC-Hq-_252D3yhH6mqIc-WUbXUPbfOtjXM,1532 +Werkzeug-0.12.1.dist-info/METADATA,sha256=QqCGwUjZaX70SDkofJYsMxbG6UfcXLb6pkvSMGKN5DA,2738 +Werkzeug-0.12.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +werkzeug/_reloader.pyc,, +werkzeug/filesystem.pyc,, +werkzeug/contrib/testtools.pyc,, +werkzeug/formparser.pyc,, +werkzeug/_compat.pyc,, +werkzeug/posixemulation.pyc,, +werkzeug/serving.pyc,, +werkzeug/contrib/__init__.pyc,, +werkzeug/contrib/iterio.pyc,, +werkzeug/datastructures.pyc,, +werkzeug/contrib/limiter.pyc,, +werkzeug/debug/tbtools.pyc,, +werkzeug/contrib/sessions.pyc,, +werkzeug/exceptions.pyc,, +werkzeug/local.pyc,, +werkzeug/utils.pyc,, +werkzeug/contrib/lint.pyc,, +werkzeug/security.pyc,, +werkzeug/contrib/cache.pyc,, +werkzeug/contrib/securecookie.pyc,, +werkzeug/script.pyc,, +werkzeug/routing.pyc,, +werkzeug/wrappers.pyc,, +werkzeug/contrib/jsrouting.pyc,, +werkzeug/contrib/fixers.pyc,, +werkzeug/contrib/profiler.pyc,, +werkzeug/debug/console.pyc,, +werkzeug/debug/__init__.pyc,, +werkzeug/wsgi.pyc,, +werkzeug/test.pyc,, +werkzeug/http.pyc,, +werkzeug/urls.pyc,, +werkzeug/useragents.pyc,, +werkzeug/_internal.pyc,, +werkzeug/contrib/wrappers.pyc,, +werkzeug/contrib/atom.pyc,, +werkzeug/__init__.pyc,, +werkzeug/testapp.pyc,, +werkzeug/debug/repr.pyc,, diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/WHEEL new file mode 100644 index 0000000..9dff69d --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.24.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/metadata.json b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/metadata.json new file mode 100644 index 0000000..4fc2cf2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"license": "BSD", "name": "Werkzeug", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "The Swiss Army knife of Python web development", "platform": "any", "run_requires": [{"requires": ["watchdog"], "extra": "watchdog"}, {"requires": ["termcolor"], "extra": "termcolor"}], "version": "0.12.1", "extensions": {"python.details": {"project_urls": {"Home": "http://werkzeug.pocoo.org/"}, "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "contacts": [{"role": "author", "email": "armin.ronacher@active-4.com", "name": "Armin Ronacher"}]}}, "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", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "extras": ["termcolor", "watchdog"]} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/top_level.txt new file mode 100644 index 0000000..6fe8da8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.12.1.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..c605ec2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/DESCRIPTION.rst @@ -0,0 +1,227 @@ + +.. image:: https://secure.travis-ci.org/ActiveState/appdirs.png + :target: http://travis-ci.org/ActiveState/appdirs + +the problem +=========== + +What directory should your app use for storing user data? If running on Mac OS X, you +should use:: + + ~/Library/Application Support/ + +If on Windows (at least English Win XP) that should be:: + + C:\Documents and Settings\\Application Data\Local Settings\\ + +or possibly:: + + C:\Documents and Settings\\Application Data\\ + +for `roaming profiles `_ but that is another story. + +On Linux (and other Unices) the dir, according to the `XDG +spec `_, is:: + + ~/.local/share/ + + +``appdirs`` to the rescue +========================= + +This kind of thing is what the ``appdirs`` module is for. ``appdirs`` will +help you choose an appropriate: + +- user data dir (``user_data_dir``) +- user config dir (``user_config_dir``) +- user cache dir (``user_cache_dir``) +- site data dir (``site_data_dir``) +- site config dir (``site_config_dir``) +- user log dir (``user_log_dir``) + +and also: + +- is a single module so other Python packages can include their own private copy +- is slightly opinionated on the directory names used. Look for "OPINION" in + documentation and code for when an opinion is being applied. + + +some example output +=================== + +On Mac OS X:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/Users/trentm/Library/Application Support/SuperApp' + >>> site_data_dir(appname, appauthor) + '/Library/Application Support/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/Users/trentm/Library/Caches/SuperApp' + >>> user_log_dir(appname, appauthor) + '/Users/trentm/Library/Logs/SuperApp' + +On Windows 7:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' + >>> user_data_dir(appname, appauthor, roaming=True) + 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' + >>> user_cache_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' + >>> user_log_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs' + +On Linux:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/home/trentm/.local/share/SuperApp + >>> site_data_dir(appname, appauthor) + '/usr/local/share/SuperApp' + >>> site_data_dir(appname, appauthor, multipath=True) + '/usr/local/share/SuperApp:/usr/share/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp' + >>> user_log_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp/log' + >>> user_config_dir(appname) + '/home/trentm/.config/SuperApp' + >>> site_config_dir(appname) + '/etc/xdg/SuperApp' + >>> os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc' + >>> site_config_dir(appname, multipath=True) + '/etc/SuperApp:/usr/local/etc/SuperApp' + + +``AppDirs`` for convenience +=========================== + +:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp' + + + +Per-version isolation +===================== + +If you have multiple versions of your app in use that you want to be +able to run side-by-side, then you may want version-isolation for these +dirs:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp/1.0' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp/1.0' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp/1.0' + + + +appdirs Changelog +================= + +appdirs 1.4.3 +------------- +- [PR #76] Python 3.6 invalid escape sequence deprecation fixes +- Fix for Python 3.6 support + +appdirs 1.4.2 +------------- +- [PR #84] Allow installing without setuptools +- [PR #86] Fix string delimiters in setup.py description +- Add Python 3.6 support + +appdirs 1.4.1 +------------- +- [issue #38] Fix _winreg import on Windows Py3 +- [issue #55] Make appname optional + +appdirs 1.4.0 +------------- +- [PR #42] AppAuthor is now optional on Windows +- [issue 41] Support Jython on Windows, Mac, and Unix-like platforms. Windows + support requires `JNA `_. +- [PR #44] Fix incorrect behaviour of the site_config_dir method + +appdirs 1.3.0 +------------- +- [Unix, issue 16] Conform to XDG standard, instead of breaking it for + everybody +- [Unix] Removes gratuitous case mangling of the case, since \*nix-es are + usually case sensitive, so mangling is not wise +- [Unix] Fixes the utterly wrong behaviour in ``site_data_dir``, return result + based on XDG_DATA_DIRS and make room for respecting the standard which + specifies XDG_DATA_DIRS is a multiple-value variable +- [Issue 6] Add ``*_config_dir`` which are distinct on nix-es, according to + XDG specs; on Windows and Mac return the corresponding ``*_data_dir`` + +appdirs 1.2.0 +------------- + +- [Unix] Put ``user_log_dir`` under the *cache* dir on Unix. Seems to be more + typical. +- [issue 9] Make ``unicode`` work on py3k. + +appdirs 1.1.0 +------------- + +- [issue 4] Add ``AppDirs.user_log_dir``. +- [Unix, issue 2, issue 7] appdirs now conforms to `XDG base directory spec + `_. +- [Mac, issue 5] Fix ``site_data_dir()`` on Mac. +- [Mac] Drop use of 'Carbon' module in favour of hardcoded paths; supports + Python3 now. +- [Windows] Append "Cache" to ``user_cache_dir`` on Windows by default. Use + ``opinion=False`` option to disable this. +- Add ``appdirs.AppDirs`` convenience class. Usage: + + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + +- [Windows] Cherry-pick Komodo's change to downgrade paths to the Windows short + paths if there are high bit chars. +- [Linux] Change default ``user_cache_dir()`` on Linux to be singular, e.g. + "~/.superapp/cache". +- [Windows] Add ``roaming`` option to ``user_data_dir()`` (for use on Windows only) + and change the default ``user_data_dir`` behaviour to use a *non*-roaming + profile dir (``CSIDL_LOCAL_APPDATA`` instead of ``CSIDL_APPDATA``). Why? Because + a large roaming profile can cause login speed issues. The "only syncs on + logout" behaviour can cause surprises in appdata info. + + +appdirs 1.0.1 (never released) +------------------------------ + +Started this changelog 27 July 2010. Before that this module originated in the +`Komodo `_ product as ``applib.py`` and then +as `applib/location.py +`_ (used by +`PyPM `_ in `ActivePython +`_). This is basically a fork of +applib.py 1.0.1 and applib/location.py 1.0.1. + + + diff --git a/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/METADATA b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/METADATA new file mode 100644 index 0000000..69ddf93 --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/METADATA @@ -0,0 +1,254 @@ +Metadata-Version: 2.0 +Name: appdirs +Version: 1.4.3 +Summary: A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir". +Home-page: http://github.com/ActiveState/appdirs +Author: Trent Mick; Sridhar Ratnakumar; Jeff Rouse +Author-email: trentm@gmail.com; github@srid.name; jr@its.to +License: MIT +Keywords: application directory log cache user +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +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.2 +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: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development :: Libraries :: Python Modules + + +.. image:: https://secure.travis-ci.org/ActiveState/appdirs.png + :target: http://travis-ci.org/ActiveState/appdirs + +the problem +=========== + +What directory should your app use for storing user data? If running on Mac OS X, you +should use:: + + ~/Library/Application Support/ + +If on Windows (at least English Win XP) that should be:: + + C:\Documents and Settings\\Application Data\Local Settings\\ + +or possibly:: + + C:\Documents and Settings\\Application Data\\ + +for `roaming profiles `_ but that is another story. + +On Linux (and other Unices) the dir, according to the `XDG +spec `_, is:: + + ~/.local/share/ + + +``appdirs`` to the rescue +========================= + +This kind of thing is what the ``appdirs`` module is for. ``appdirs`` will +help you choose an appropriate: + +- user data dir (``user_data_dir``) +- user config dir (``user_config_dir``) +- user cache dir (``user_cache_dir``) +- site data dir (``site_data_dir``) +- site config dir (``site_config_dir``) +- user log dir (``user_log_dir``) + +and also: + +- is a single module so other Python packages can include their own private copy +- is slightly opinionated on the directory names used. Look for "OPINION" in + documentation and code for when an opinion is being applied. + + +some example output +=================== + +On Mac OS X:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/Users/trentm/Library/Application Support/SuperApp' + >>> site_data_dir(appname, appauthor) + '/Library/Application Support/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/Users/trentm/Library/Caches/SuperApp' + >>> user_log_dir(appname, appauthor) + '/Users/trentm/Library/Logs/SuperApp' + +On Windows 7:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' + >>> user_data_dir(appname, appauthor, roaming=True) + 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' + >>> user_cache_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' + >>> user_log_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs' + +On Linux:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/home/trentm/.local/share/SuperApp + >>> site_data_dir(appname, appauthor) + '/usr/local/share/SuperApp' + >>> site_data_dir(appname, appauthor, multipath=True) + '/usr/local/share/SuperApp:/usr/share/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp' + >>> user_log_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp/log' + >>> user_config_dir(appname) + '/home/trentm/.config/SuperApp' + >>> site_config_dir(appname) + '/etc/xdg/SuperApp' + >>> os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc' + >>> site_config_dir(appname, multipath=True) + '/etc/SuperApp:/usr/local/etc/SuperApp' + + +``AppDirs`` for convenience +=========================== + +:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp' + + + +Per-version isolation +===================== + +If you have multiple versions of your app in use that you want to be +able to run side-by-side, then you may want version-isolation for these +dirs:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp/1.0' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp/1.0' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp/1.0' + + + +appdirs Changelog +================= + +appdirs 1.4.3 +------------- +- [PR #76] Python 3.6 invalid escape sequence deprecation fixes +- Fix for Python 3.6 support + +appdirs 1.4.2 +------------- +- [PR #84] Allow installing without setuptools +- [PR #86] Fix string delimiters in setup.py description +- Add Python 3.6 support + +appdirs 1.4.1 +------------- +- [issue #38] Fix _winreg import on Windows Py3 +- [issue #55] Make appname optional + +appdirs 1.4.0 +------------- +- [PR #42] AppAuthor is now optional on Windows +- [issue 41] Support Jython on Windows, Mac, and Unix-like platforms. Windows + support requires `JNA `_. +- [PR #44] Fix incorrect behaviour of the site_config_dir method + +appdirs 1.3.0 +------------- +- [Unix, issue 16] Conform to XDG standard, instead of breaking it for + everybody +- [Unix] Removes gratuitous case mangling of the case, since \*nix-es are + usually case sensitive, so mangling is not wise +- [Unix] Fixes the utterly wrong behaviour in ``site_data_dir``, return result + based on XDG_DATA_DIRS and make room for respecting the standard which + specifies XDG_DATA_DIRS is a multiple-value variable +- [Issue 6] Add ``*_config_dir`` which are distinct on nix-es, according to + XDG specs; on Windows and Mac return the corresponding ``*_data_dir`` + +appdirs 1.2.0 +------------- + +- [Unix] Put ``user_log_dir`` under the *cache* dir on Unix. Seems to be more + typical. +- [issue 9] Make ``unicode`` work on py3k. + +appdirs 1.1.0 +------------- + +- [issue 4] Add ``AppDirs.user_log_dir``. +- [Unix, issue 2, issue 7] appdirs now conforms to `XDG base directory spec + `_. +- [Mac, issue 5] Fix ``site_data_dir()`` on Mac. +- [Mac] Drop use of 'Carbon' module in favour of hardcoded paths; supports + Python3 now. +- [Windows] Append "Cache" to ``user_cache_dir`` on Windows by default. Use + ``opinion=False`` option to disable this. +- Add ``appdirs.AppDirs`` convenience class. Usage: + + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + +- [Windows] Cherry-pick Komodo's change to downgrade paths to the Windows short + paths if there are high bit chars. +- [Linux] Change default ``user_cache_dir()`` on Linux to be singular, e.g. + "~/.superapp/cache". +- [Windows] Add ``roaming`` option to ``user_data_dir()`` (for use on Windows only) + and change the default ``user_data_dir`` behaviour to use a *non*-roaming + profile dir (``CSIDL_LOCAL_APPDATA`` instead of ``CSIDL_APPDATA``). Why? Because + a large roaming profile can cause login speed issues. The "only syncs on + logout" behaviour can cause surprises in appdata info. + + +appdirs 1.0.1 (never released) +------------------------------ + +Started this changelog 27 July 2010. Before that this module originated in the +`Komodo `_ product as ``applib.py`` and then +as `applib/location.py +`_ (used by +`PyPM `_ in `ActivePython +`_). This is basically a fork of +applib.py 1.0.1 and applib/location.py 1.0.1. + + + diff --git a/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/RECORD b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/RECORD new file mode 100644 index 0000000..3988f91 --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/RECORD @@ -0,0 +1,9 @@ +appdirs.py,sha256=MievUEuv3l_mQISH5SF0shDk_BNhHHzYiAPrT3ITN4I,24701 +appdirs-1.4.3.dist-info/DESCRIPTION.rst,sha256=77Fe8OIOLSjDSNdLiL5xywMKO-AGE42rdXkqKo4Ee-k,7531 +appdirs-1.4.3.dist-info/METADATA,sha256=3IFw6jTfImdOqsCb2GYvVR157tL7KEzfRAszn382csk,8773 +appdirs-1.4.3.dist-info/RECORD,, +appdirs-1.4.3.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 +appdirs-1.4.3.dist-info/metadata.json,sha256=fL_Q-GuFJu3PJxMrwU7SdsI8RGqjIfi2AvouCSF5DSA,1359 +appdirs-1.4.3.dist-info/top_level.txt,sha256=nKncE8CUqZERJ6VuQWL4_bkunSPDNfn7KZqb4Tr5YEM,8 +appdirs-1.4.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +appdirs.pyc,, diff --git a/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/WHEEL b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/WHEEL new file mode 100644 index 0000000..8b6dd1b --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/metadata.json b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/metadata.json new file mode 100644 index 0000000..da1e5f3 --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Python Modules"], "extensions": {"python.details": {"contacts": [{"email": "trentm@gmail.com; github@srid.name; jr@its.to", "name": "Trent Mick; Sridhar Ratnakumar; Jeff Rouse", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://github.com/ActiveState/appdirs"}}}, "generator": "bdist_wheel (0.29.0)", "keywords": ["application", "directory", "log", "cache", "user"], "license": "MIT", "metadata_version": "2.0", "name": "appdirs", "summary": "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\".", "test_requires": [{"requires": []}], "version": "1.4.3"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/top_level.txt new file mode 100644 index 0000000..d64bc32 --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs-1.4.3.dist-info/top_level.txt @@ -0,0 +1 @@ +appdirs diff --git a/venv/lib/python2.7/site-packages/appdirs.py b/venv/lib/python2.7/site-packages/appdirs.py new file mode 100644 index 0000000..ae67001 --- /dev/null +++ b/venv/lib/python2.7/site-packages/appdirs.py @@ -0,0 +1,608 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2005-2010 ActiveState Software Inc. +# Copyright (c) 2013 Eddy Petrișor + +"""Utilities for determining application-specific dirs. + +See for details and usage. +""" +# Dev Notes: +# - MSDN on where to store app data files: +# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 +# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html +# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + +__version_info__ = (1, 4, 3) +__version__ = '.'.join(map(str, __version_info__)) + + +import sys +import os + +PY3 = sys.version_info[0] == 3 + +if PY3: + unicode = str + +if sys.platform.startswith('java'): + import platform + os_name = platform.java_ver()[3][0] + if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc. + system = 'win32' + elif os_name.startswith('Mac'): # "Mac OS X", etc. + system = 'darwin' + else: # "Linux", "SunOS", "FreeBSD", etc. + # Setting this to "linux2" is not ideal, but only Windows or Mac + # are actually checked for and the rest of the module expects + # *sys.platform* style strings. + system = 'linux2' +else: + system = sys.platform + + + +def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user data directories are: + Mac OS X: ~/Library/Application Support/ + Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined + Win XP (not roaming): C:\Documents and Settings\\Application Data\\ + Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\ + Win 7 (not roaming): C:\Users\\AppData\Local\\ + Win 7 (roaming): C:\Users\\AppData\Roaming\\ + + For Unix, we follow the XDG spec and support $XDG_DATA_HOME. + That means, by default "~/.local/share/". + """ + if system == "win32": + if appauthor is None: + appauthor = appname + const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" + path = os.path.normpath(_get_win_folder(const)) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('~/Library/Application Support/') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of data dirs should be + returned. By default, the first item from XDG_DATA_DIRS is + returned, or '/usr/local/share/', + if XDG_DATA_DIRS is not set + + Typical site data directories are: + Mac OS X: /Library/Application Support/ + Unix: /usr/local/share/ or /usr/share/ + Win XP: C:\Documents and Settings\All Users\Application Data\\ + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + Win 7: C:\ProgramData\\ # Hidden, but writeable on Win 7. + + For Unix, this is using the $XDG_DATA_DIRS[0] default. + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('/Library/Application Support') + if appname: + path = os.path.join(path, appname) + else: + # XDG default for $XDG_DATA_DIRS + # only first, if multipath is False + path = os.getenv('XDG_DATA_DIRS', + os.pathsep.join(['/usr/local/share', '/usr/share'])) + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + if appname and version: + path = os.path.join(path, version) + return path + + +def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific config dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user config directories are: + Mac OS X: same as user_data_dir + Unix: ~/.config/ # or in $XDG_CONFIG_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. + That means, by default "~/.config/". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of config dirs should be + returned. By default, the first item from XDG_CONFIG_DIRS is + returned, or '/etc/xdg/', if XDG_CONFIG_DIRS is not set + + Typical site config directories are: + Mac OS X: same as site_data_dir + Unix: /etc/xdg/ or $XDG_CONFIG_DIRS[i]/ for each value in + $XDG_CONFIG_DIRS + Win *: same as site_data_dir + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + + For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system in ["win32", "darwin"]: + path = site_data_dir(appname, appauthor) + if appname and version: + path = os.path.join(path, version) + else: + # XDG default for $XDG_CONFIG_DIRS + # only first, if multipath is False + path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + +def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific cache dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Cache" to the base app data dir for Windows. See + discussion below. + + Typical user cache directories are: + Mac OS X: ~/Library/Caches/ + Unix: ~/.cache/ (XDG default) + Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Cache + Vista: C:\Users\\AppData\Local\\\Cache + + On Windows the only suggestion in the MSDN docs is that local settings go in + the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming + app data dir (the default returned by `user_data_dir` above). Apps typically + put cache data somewhere *under* the given dir here. Some examples: + ...\Mozilla\Firefox\Profiles\\Cache + ...\Acme\SuperApp\Cache\1.0 + OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. + This can be disabled with the `opinion=False` option. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + if opinion: + path = os.path.join(path, "Cache") + elif system == 'darwin': + path = os.path.expanduser('~/Library/Caches') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific state dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user state directories are: + Mac OS X: same as user_data_dir + Unix: ~/.local/state/ # or in $XDG_STATE_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow this Debian proposal + to extend the XDG spec and support $XDG_STATE_HOME. + + That means, by default "~/.local/state/". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific log dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Logs" to the base app data dir for Windows, and "log" to the + base cache dir for Unix. See discussion below. + + Typical user log directories are: + Mac OS X: ~/Library/Logs/ + Unix: ~/.cache//log # or under $XDG_CACHE_HOME if defined + Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Logs + Vista: C:\Users\\AppData\Local\\\Logs + + On Windows the only suggestion in the MSDN docs is that local settings + go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in + examples of what some windows apps use for a logs dir.) + + OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` + value for Windows and appends "log" to the user cache dir for Unix. + This can be disabled with the `opinion=False` option. + """ + if system == "darwin": + path = os.path.join( + os.path.expanduser('~/Library/Logs'), + appname) + elif system == "win32": + path = user_data_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "Logs") + else: + path = user_cache_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "log") + if appname and version: + path = os.path.join(path, version) + return path + + +class AppDirs(object): + """Convenience wrapper for getting application dirs.""" + def __init__(self, appname=None, appauthor=None, version=None, + roaming=False, multipath=False): + self.appname = appname + self.appauthor = appauthor + self.version = version + self.roaming = roaming + self.multipath = multipath + + @property + def user_data_dir(self): + return user_data_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_data_dir(self): + return site_data_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_config_dir(self): + return user_config_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_config_dir(self): + return site_config_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_cache_dir(self): + return user_cache_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_state_dir(self): + return user_state_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_log_dir(self): + return user_log_dir(self.appname, self.appauthor, + version=self.version) + + +#---- internal support stuff + +def _get_win_folder_from_registry(csidl_name): + """This is a fallback technique at best. I'm not sure if using the + registry for this guarantees us the correct answer for all CSIDL_* + names. + """ + if PY3: + import winreg as _winreg + else: + import _winreg + + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + }[csidl_name] + + key = _winreg.OpenKey( + _winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" + ) + dir, type = _winreg.QueryValueEx(key, shell_folder_name) + return dir + + +def _get_win_folder_with_pywin32(csidl_name): + from win32com.shell import shellcon, shell + dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) + # Try to make this a unicode path because SHGetFolderPath does + # not return unicode strings when there is unicode data in the + # path. + try: + dir = unicode(dir) + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + try: + import win32api + dir = win32api.GetShortPathName(dir) + except ImportError: + pass + except UnicodeError: + pass + return dir + + +def _get_win_folder_with_ctypes(csidl_name): + import ctypes + + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + }[csidl_name] + + buf = ctypes.create_unicode_buffer(1024) + ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in buf: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf2 = ctypes.create_unicode_buffer(1024) + if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + return buf.value + +def _get_win_folder_with_jna(csidl_name): + import array + from com.sun import jna + from com.sun.jna.platform import win32 + + buf_size = win32.WinDef.MAX_PATH * 2 + buf = array.zeros('c', buf_size) + shell = win32.Shell32.INSTANCE + shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf) + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf = array.zeros('c', buf_size) + kernel = win32.Kernel32.INSTANCE + if kernel.GetShortPathName(dir, buf, buf_size): + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + return dir + +if system == "win32": + try: + import win32com.shell + _get_win_folder = _get_win_folder_with_pywin32 + except ImportError: + try: + from ctypes import windll + _get_win_folder = _get_win_folder_with_ctypes + except ImportError: + try: + import com.sun.jna + _get_win_folder = _get_win_folder_with_jna + except ImportError: + _get_win_folder = _get_win_folder_from_registry + + +#---- self test code + +if __name__ == "__main__": + appname = "MyApp" + appauthor = "MyCompany" + + props = ("user_data_dir", + "user_config_dir", + "user_cache_dir", + "user_state_dir", + "user_log_dir", + "site_data_dir", + "site_config_dir") + + print("-- app dirs %s --" % __version__) + + print("-- app dirs (with optional 'version')") + dirs = AppDirs(appname, appauthor, version="1.0") + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'version')") + dirs = AppDirs(appname, appauthor) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'appauthor')") + dirs = AppDirs(appname) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (with disabled 'appauthor')") + dirs = AppDirs(appname, appauthor=False) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) diff --git a/venv/lib/python2.7/site-packages/appdirs.pyc b/venv/lib/python2.7/site-packages/appdirs.pyc new file mode 100644 index 0000000..43b4ac9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/appdirs.pyc differ diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/click-6.7.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..e118723 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/DESCRIPTION.rst @@ -0,0 +1,3 @@ +UNKNOWN + + diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/click-6.7.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/METADATA b/venv/lib/python2.7/site-packages/click-6.7.dist-info/METADATA new file mode 100644 index 0000000..1f10885 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/METADATA @@ -0,0 +1,16 @@ +Metadata-Version: 2.0 +Name: click +Version: 6.7 +Summary: A simple wrapper around optparse for powerful command line utilities. +Home-page: http://github.com/mitsuhiko/click +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: UNKNOWN +Platform: UNKNOWN +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 + +UNKNOWN + + diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/RECORD b/venv/lib/python2.7/site-packages/click-6.7.dist-info/RECORD new file mode 100644 index 0000000..fd18d4e --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/RECORD @@ -0,0 +1,41 @@ +click/__init__.py,sha256=k8R00cFKWI8dhDVKQeLBlAdNh1CxerMEDRiGnr32gdw,2858 +click/_bashcomplete.py,sha256=82rMiibtEurdwBq60NHXVCBuGXJHDpblFO9o2YxJDF0,2423 +click/_compat.py,sha256=j59MpzxYGE-fTGj0A5sg8UI8GhHod1XMojiCA0jvbL0,21011 +click/_termui_impl.py,sha256=Ol1JJhvBRw3l8j1WIU0tOWjQtxxmwGE44lFDbzDqzoA,16395 +click/_textwrap.py,sha256=gwS4m7bdQiJnzaDG8osFcRb-5vn4t4l2qSCy-5csCEc,1198 +click/_unicodefun.py,sha256=A3UOzJw6lEZyol2SBg3fNXgweTutaOzkJ61OB7vik3Y,4204 +click/_winconsole.py,sha256=MzG46DEYPoRyx4SO7EIhFuFZHESgooAfJLIukbB6p5c,7790 +click/core.py,sha256=M0nJ6Kkye7XZXYG7HCbkJWSfy14WHV6bQmGLACrOhKw,70254 +click/decorators.py,sha256=y7CX2needh8iRWafj-QS_hGQFsN24eyXAhx5Y2ATwas,10941 +click/exceptions.py,sha256=rOa0pP3PbSy0_AAPOW9irBEM8AJ3BySN-4z2VUwFVo4,6788 +click/formatting.py,sha256=eh-cypTUAhpI3HD-K4ZpR3vCiURIO62xXvKkR3tNUTM,8889 +click/globals.py,sha256=PAgnKvGxq4YuEIldw3lgYOGBLYwsyxnm1IByBX3BFXo,1515 +click/parser.py,sha256=i01xgYuIA6AwQWEXjshwHSwnTR3gUep4FxJIfyW4ta4,15510 +click/termui.py,sha256=Bp99MSWQtyoWe1_7HggDmA77n--3KLxu7NsZMFMaCUo,21008 +click/testing.py,sha256=kJ9mjtJgwNAlkgKcFf9-ISxufmaPDbbuOHVC9WIvKdY,11002 +click/types.py,sha256=ZGb2lmFs5Vwd9loTRIMbGcqhPVOql8mGoBhWBRT6V4E,18864 +click/utils.py,sha256=1jalPlkUU28JReTEQeeSFtbJd-SirYWBNfjtELBKzT4,14916 +click-6.7.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10 +click-6.7.dist-info/METADATA,sha256=l6lAyogIUXiHKUK_rWguef-EMcvO5C6bXzFCNCcblbQ,424 +click-6.7.dist-info/RECORD,, +click-6.7.dist-info/WHEEL,sha256=5wvfB7GvgZAbKBSE9uX9Zbi6LCL-_KgezgHblXhCRnM,113 +click-6.7.dist-info/metadata.json,sha256=qg0uO6amNHkIkOxnmWX7Xa_DNQMQ62Q6drivuP9Gh1c,571 +click-6.7.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click-6.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click/exceptions.pyc,, +click/_unicodefun.pyc,, +click/_compat.pyc,, +click/_textwrap.pyc,, +click/formatting.pyc,, +click/decorators.pyc,, +click/_bashcomplete.pyc,, +click/parser.pyc,, +click/testing.pyc,, +click/utils.pyc,, +click/types.pyc,, +click/termui.pyc,, +click/core.pyc,, +click/_winconsole.pyc,, +click/__init__.pyc,, +click/_termui_impl.pyc,, +click/globals.pyc,, diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/WHEEL b/venv/lib/python2.7/site-packages/click-6.7.dist-info/WHEEL new file mode 100644 index 0000000..7bf9daa --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0.a0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/metadata.json b/venv/lib/python2.7/site-packages/click-6.7.dist-info/metadata.json new file mode 100644 index 0000000..0a4cfb1 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 3"], "extensions": {"python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://github.com/mitsuhiko/click"}}}, "generator": "bdist_wheel (0.30.0.a0)", "metadata_version": "2.0", "name": "click", "summary": "A simple wrapper around optparse for powerful command line utilities.", "version": "6.7"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/click-6.7.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/venv/lib/python2.7/site-packages/click/__init__.py b/venv/lib/python2.7/site-packages/click/__init__.py new file mode 100644 index 0000000..971e55d --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/__init__.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +""" + click + ~~~~~ + + Click is a simple Python module that wraps the stdlib's 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. + + In case optparse ever gets removed from the stdlib, it will be shipped by + this module. + + :copyright: (c) 2014 by Armin Ronacher. + :license: BSD, see LICENSE 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, \ + STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED + +# 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', 'STRING', + 'INT', 'FLOAT', 'BOOL', 'UUID', 'UNPROCESSED', + + # 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__ = '6.7' diff --git a/venv/lib/python2.7/site-packages/click/__init__.pyc b/venv/lib/python2.7/site-packages/click/__init__.pyc new file mode 100644 index 0000000..659a46b Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/__init__.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/_bashcomplete.py b/venv/lib/python2.7/site-packages/click/_bashcomplete.py new file mode 100644 index 0000000..d9d26d2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_bashcomplete.py @@ -0,0 +1,83 @@ +import os +import re +from .utils import echo +from .parser import split_arg_string +from .core import MultiCommand, Option + + +COMPLETION_SCRIPT = ''' +%(complete_func)s() { + COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + %(autocomplete_var)s=complete $1 ) ) + return 0 +} + +complete -F %(complete_func)s -o default %(script_names)s +''' + +_invalid_ident_char_re = re.compile(r'[^a-zA-Z0-9_]') + + +def get_completion_script(prog_name, complete_var): + cf_name = _invalid_ident_char_re.sub('', prog_name.replace('-', '_')) + return (COMPLETION_SCRIPT % { + 'complete_func': '_%s_completion' % cf_name, + 'script_names': prog_name, + 'autocomplete_var': complete_var, + }).strip() + ';' + + +def resolve_ctx(cli, prog_name, args): + ctx = cli.make_context(prog_name, args, resilient_parsing=True) + while ctx.protected_args + ctx.args and isinstance(ctx.command, MultiCommand): + a = ctx.protected_args + ctx.args + cmd = ctx.command.get_command(ctx, a[0]) + if cmd is None: + return None + ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True) + return ctx + + +def get_choices(cli, prog_name, args, incomplete): + ctx = resolve_ctx(cli, prog_name, args) + if ctx is None: + return + + choices = [] + if incomplete and not incomplete[:1].isalnum(): + for param in ctx.command.params: + if not isinstance(param, Option): + continue + choices.extend(param.opts) + choices.extend(param.secondary_opts) + elif isinstance(ctx.command, MultiCommand): + choices.extend(ctx.command.list_commands(ctx)) + + for item in choices: + if item.startswith(incomplete): + yield item + + +def do_complete(cli, prog_name): + cwords = split_arg_string(os.environ['COMP_WORDS']) + cword = int(os.environ['COMP_CWORD']) + args = cwords[1:cword] + try: + incomplete = cwords[cword] + except IndexError: + incomplete = '' + + for item in get_choices(cli, prog_name, args, incomplete): + echo(item) + + return True + + +def bashcomplete(cli, prog_name, complete_var, complete_instr): + if complete_instr == 'source': + echo(get_completion_script(prog_name, complete_var)) + return True + elif complete_instr == 'complete': + return do_complete(cli, prog_name) + return False diff --git a/venv/lib/python2.7/site-packages/click/_bashcomplete.pyc b/venv/lib/python2.7/site-packages/click/_bashcomplete.pyc new file mode 100644 index 0000000..84e5fcc Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/_bashcomplete.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/_compat.py b/venv/lib/python2.7/site-packages/click/_compat.py new file mode 100644 index 0000000..2b43412 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_compat.py @@ -0,0 +1,648 @@ +import re +import io +import os +import sys +import codecs +from weakref import WeakKeyDictionary + + +PY2 = sys.version_info[0] == 2 +WIN = sys.platform.startswith('win') +DEFAULT_COLUMNS = 80 + + +_ansi_re = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') + + +def get_filesystem_encoding(): + return sys.getfilesystemencoding() or sys.getdefaultencoding() + + +def _make_text_stream(stream, encoding, errors): + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = 'replace' + return _NonClosingTextIOWrapper(stream, encoding, errors, + line_buffering=True) + + +def is_ascii_encoding(encoding): + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == 'ascii' + except LookupError: + return False + + +def get_best_encoding(stream): + """Returns the default stream encoding if not found.""" + rv = getattr(stream, 'encoding', None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return 'utf-8' + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + + def __init__(self, stream, encoding, errors, **extra): + self._stream = stream = _FixupStream(stream) + io.TextIOWrapper.__init__(self, stream, encoding, errors, **extra) + + # The io module is a place where the Python 3 text behavior + # was forced upon Python 2, so we need to unbreak + # it to look like Python 2. + if PY2: + def write(self, x): + if isinstance(x, str) or is_bytes(x): + try: + self.flush() + except Exception: + pass + return self.buffer.write(str(x)) + return io.TextIOWrapper.write(self, x) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def __del__(self): + try: + self.detach() + except Exception: + pass + + def isatty(self): + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream(object): + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + """ + + def __init__(self, stream): + self._stream = stream + + def __getattr__(self, name): + return getattr(self._stream, name) + + def read1(self, size): + f = getattr(self._stream, 'read1', None) + if f is not None: + return f(size) + # We only dispatch to readline instead of read in Python 2 as we + # do not want cause problems with the different implementation + # of line buffering. + if PY2: + return self._stream.readline(size) + return self._stream.read(size) + + def readable(self): + x = getattr(self._stream, 'readable', None) + if x is not None: + return x() + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self): + x = getattr(self._stream, 'writable', None) + if x is not None: + return x() + try: + self._stream.write('') + except Exception: + try: + self._stream.write(b'') + except Exception: + return False + return True + + def seekable(self): + x = getattr(self._stream, 'seekable', None) + if x is not None: + return x() + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +if PY2: + text_type = unicode + bytes = str + raw_input = raw_input + string_types = (str, unicode) + iteritems = lambda x: x.iteritems() + range_type = xrange + + def is_bytes(x): + return isinstance(x, (buffer, bytearray)) + + _identifier_re = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$') + + # For Windows, we need to force stdout/stdin/stderr to binary if it's + # fetched for that. This obviously is not the most correct way to do + # it as it changes global state. Unfortunately, there does not seem to + # be a clear better way to do it as just reopening the file in binary + # mode does not change anything. + # + # An option would be to do what Python 3 does and to open the file as + # binary only, patch it back to the system, and then use a wrapper + # stream that converts newlines. It's not quite clear what's the + # correct option here. + # + # This code also lives in _winconsole for the fallback to the console + # emulation stream. + # + # There are also Windows environments where the `msvcrt` module is not + # available (which is why we use try-catch instead of the WIN variable + # here), such as the Google App Engine development server on Windows. In + # those cases there is just nothing we can do. + try: + import msvcrt + except ImportError: + set_binary_mode = lambda x: x + else: + def set_binary_mode(f): + try: + fileno = f.fileno() + except Exception: + pass + else: + msvcrt.setmode(fileno, os.O_BINARY) + return f + + def isidentifier(x): + return _identifier_re.search(x) is not None + + def get_binary_stdin(): + return set_binary_mode(sys.stdin) + + def get_binary_stdout(): + return set_binary_mode(sys.stdout) + + def get_binary_stderr(): + return set_binary_mode(sys.stderr) + + def get_text_stdin(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stdin, encoding, errors) + + def get_text_stdout(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stdout, encoding, errors) + + def get_text_stderr(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stderr, encoding, errors) + + def filename_to_ui(value): + if isinstance(value, bytes): + value = value.decode(get_filesystem_encoding(), 'replace') + return value +else: + import io + text_type = str + raw_input = input + string_types = (str,) + range_type = range + isidentifier = lambda x: x.isidentifier() + iteritems = lambda x: iter(x.items()) + + def is_bytes(x): + return isinstance(x, (bytes, memoryview, bytearray)) + + def _is_binary_reader(stream, default=False): + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + def _is_binary_writer(stream, default=False): + try: + stream.write(b'') + except Exception: + try: + stream.write('') + return False + except Exception: + pass + return default + return True + + def _find_binary_reader(stream): + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return stream + + buf = getattr(stream, 'buffer', None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return buf + + def _find_binary_writer(stream): + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detatching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return stream + + buf = getattr(stream, 'buffer', None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return buf + + def _stream_is_misconfigured(stream): + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, 'encoding', None) or 'ascii') + + def _is_compatible_text_stream(stream, encoding, errors): + stream_encoding = getattr(stream, 'encoding', None) + stream_errors = getattr(stream, 'errors', None) + + # Perfect match. + if stream_encoding == encoding and stream_errors == errors: + return True + + # Otherwise, it's only a compatible stream if we did not ask for + # an encoding. + if encoding is None: + return stream_encoding is not None + + return False + + def _force_correct_text_reader(text_reader, encoding, errors): + if _is_binary_reader(text_reader, False): + binary_reader = text_reader + else: + # If there is no target encoding set, we need to verify that the + # reader is not actually misconfigured. + if encoding is None and not _stream_is_misconfigured(text_reader): + return text_reader + + if _is_compatible_text_stream(text_reader, encoding, errors): + return text_reader + + # If the reader has no encoding, we try to find the underlying + # binary reader for it. If that fails because the environment is + # misconfigured, we silently go with the same reader because this + # is too common to happen. In that case, mojibake is better than + # exceptions. + binary_reader = _find_binary_reader(text_reader) + if binary_reader is None: + return text_reader + + # At this point, we default the errors to replace instead of strict + # because nobody handles those errors anyways and at this point + # we're so fundamentally fucked that nothing can repair it. + if errors is None: + errors = 'replace' + return _make_text_stream(binary_reader, encoding, errors) + + def _force_correct_text_writer(text_writer, encoding, errors): + if _is_binary_writer(text_writer, False): + binary_writer = text_writer + else: + # If there is no target encoding set, we need to verify that the + # writer is not actually misconfigured. + if encoding is None and not _stream_is_misconfigured(text_writer): + return text_writer + + if _is_compatible_text_stream(text_writer, encoding, errors): + return text_writer + + # If the writer has no encoding, we try to find the underlying + # binary writer for it. If that fails because the environment is + # misconfigured, we silently go with the same writer because this + # is too common to happen. In that case, mojibake is better than + # exceptions. + binary_writer = _find_binary_writer(text_writer) + if binary_writer is None: + return text_writer + + # At this point, we default the errors to replace instead of strict + # because nobody handles those errors anyways and at this point + # we're so fundamentally fucked that nothing can repair it. + if errors is None: + errors = 'replace' + return _make_text_stream(binary_writer, encoding, errors) + + def get_binary_stdin(): + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError('Was not able to determine binary ' + 'stream for sys.stdin.') + return reader + + def get_binary_stdout(): + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError('Was not able to determine binary ' + 'stream for sys.stdout.') + return writer + + def get_binary_stderr(): + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError('Was not able to determine binary ' + 'stream for sys.stderr.') + return writer + + def get_text_stdin(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors) + + def get_text_stdout(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors) + + def get_text_stderr(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors) + + def filename_to_ui(value): + if isinstance(value, bytes): + value = value.decode(get_filesystem_encoding(), 'replace') + else: + value = value.encode('utf-8', 'surrogateescape') \ + .decode('utf-8', 'replace') + return value + + +def get_streerror(e, default=None): + if hasattr(e, 'strerror'): + msg = e.strerror + else: + if default is not None: + msg = default + else: + msg = str(e) + if isinstance(msg, bytes): + msg = msg.decode('utf-8', 'replace') + return msg + + +def open_stream(filename, mode='r', encoding=None, errors='strict', + atomic=False): + # Standard streams first. These are simple because they don't need + # special handling for the atomic flag. It's entirely ignored. + if filename == '-': + if 'w' in mode: + if 'b' in mode: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if 'b' in mode: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + if encoding is None: + return open(filename, mode), True + return io.open(filename, mode, encoding=encoding, errors=errors), True + + # Some usability stuff for atomic writes + if 'a' in mode: + raise ValueError( + 'Appending to an existing file is not supported, because that ' + 'would involve an expensive `copy`-operation to a temporary ' + 'file. Open the file in normal `w`-mode and copy explicitly ' + 'if that\'s what you\'re after.' + ) + if 'x' in mode: + raise ValueError('Use the `overwrite`-parameter instead.') + if 'w' not in mode: + raise ValueError('Atomic writes only make sense with `w`-mode.') + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import tempfile + fd, tmp_filename = tempfile.mkstemp(dir=os.path.dirname(filename), + prefix='.__atomic-write') + + if encoding is not None: + f = io.open(fd, mode, encoding=encoding, errors=errors) + else: + f = os.fdopen(fd, mode) + + return _AtomicFile(f, tmp_filename, filename), True + + +# Used in a destructor call, needs extra protection from interpreter cleanup. +if hasattr(os, 'replace'): + _replace = os.replace + _can_replace = True +else: + _replace = os.rename + _can_replace = not WIN + + +class _AtomicFile(object): + + def __init__(self, f, tmp_filename, real_filename): + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self): + return self._real_filename + + def close(self, delete=False): + if self.closed: + return + self._f.close() + if not _can_replace: + try: + os.remove(self._real_filename) + except OSError: + pass + _replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name): + return getattr(self._f, name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.close(delete=exc_type is not None) + + def __repr__(self): + return repr(self._f) + + +auto_wrap_for_ansi = None +colorama = None +get_winterm_size = None + + +def strip_ansi(value): + return _ansi_re.sub('', value) + + +def should_strip_ansi(stream=None, color=None): + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) + return not color + + +# If we're on Windows, we provide transparent integration through +# colorama. This will make ANSI colors through the echo function +# work automatically. +if WIN: + # Windows has a smaller terminal + DEFAULT_COLUMNS = 79 + + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding(): + import locale + return locale.getpreferredencoding() + + if PY2: + def raw_input(prompt=''): + sys.stderr.flush() + if prompt: + stdout = _default_text_stdout() + stdout.write(prompt) + stdin = _default_text_stdin() + return stdin.readline().rstrip('\r\n') + + try: + import colorama + except ImportError: + pass + else: + _ansi_stream_wrappers = WeakKeyDictionary() + + def auto_wrap_for_ansi(stream, color=None): + """This function wraps a stream so that calls through colorama + are issued to the win32 console API to recolor on demand. It + also ensures to reset the colors if a write call is interrupted + to not destroy the console afterwards. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + if cached is not None: + return cached + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = ansi_wrapper.stream + _write = rv.write + + def _safe_write(s): + try: + return _write(s) + except: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + return rv + + def get_winterm_size(): + win = colorama.win32.GetConsoleScreenBufferInfo( + colorama.win32.STDOUT).srWindow + return win.Right - win.Left, win.Bottom - win.Top +else: + def _get_argv_encoding(): + return getattr(sys.stdin, 'encoding', None) or get_filesystem_encoding() + + _get_windows_console_stream = lambda *x: None + + +def term_len(x): + return len(strip_ansi(x)) + + +def isatty(stream): + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func(src_func, wrapper_func): + cache = WeakKeyDictionary() + def func(): + stream = src_func() + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + return func + + +_default_text_stdin = _make_cached_stream_func( + lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func( + lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func( + lambda: sys.stderr, get_text_stderr) + + +binary_streams = { + 'stdin': get_binary_stdin, + 'stdout': get_binary_stdout, + 'stderr': get_binary_stderr, +} + +text_streams = { + 'stdin': get_text_stdin, + 'stdout': get_text_stdout, + 'stderr': get_text_stderr, +} diff --git a/venv/lib/python2.7/site-packages/click/_compat.pyc b/venv/lib/python2.7/site-packages/click/_compat.pyc new file mode 100644 index 0000000..cd16a6f Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/_compat.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/_termui_impl.py b/venv/lib/python2.7/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..7cfd3d5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_termui_impl.py @@ -0,0 +1,547 @@ +""" + click._termui_impl + ~~~~~~~~~~~~~~~~~~ + + This module contains implementations for the termui module. To keep the + import time of Click down, some infrequently used functionality is placed + in this module and only imported as needed. + + :copyright: (c) 2014 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import os +import sys +import time +import math +from ._compat import _default_text_stdout, range_type, PY2, isatty, \ + open_stream, strip_ansi, term_len, get_best_encoding, WIN +from .utils import echo +from .exceptions import ClickException + + +if os.name == 'nt': + BEFORE_BAR = '\r' + AFTER_BAR = '\n' +else: + BEFORE_BAR = '\r\033[?25l' + AFTER_BAR = '\033[?25h\n' + + +def _length_hint(obj): + """Returns the length hint of an object.""" + try: + return len(obj) + except (AttributeError, TypeError): + try: + get_hint = type(obj).__length_hint__ + except AttributeError: + return None + try: + hint = get_hint(obj) + except TypeError: + return None + if hint is NotImplemented or \ + not isinstance(hint, (int, long)) or \ + hint < 0: + return None + return hint + + +class ProgressBar(object): + + def __init__(self, iterable, length=None, fill_char='#', empty_char=' ', + bar_template='%(bar)s', info_sep=' ', show_eta=True, + show_percent=None, show_pos=False, item_show_func=None, + label=None, file=None, color=None, width=30): + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label = label or '' + if file is None: + file = _default_text_stdout() + self.file = file + self.color = color + self.width = width + self.autowidth = width == 0 + + if length is None: + length = _length_hint(iterable) + if iterable is None: + if length is None: + raise TypeError('iterable or length is required') + iterable = range_type(length) + self.iter = iter(iterable) + self.length = length + self.length_known = length is not None + self.pos = 0 + self.avg = [] + self.start = self.last_eta = time.time() + self.eta_known = False + self.finished = False + self.max_width = None + self.entered = False + self.current_item = None + self.is_hidden = not isatty(self.file) + self._last_line = None + + def __enter__(self): + self.entered = True + self.render_progress() + return self + + def __exit__(self, exc_type, exc_value, tb): + self.render_finish() + + def __iter__(self): + if not self.entered: + raise RuntimeError('You need to use progress bars in a with block.') + self.render_progress() + return self + + def render_finish(self): + if self.is_hidden: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self): + if self.finished: + return 1.0 + return min(self.pos / (float(self.length) or 1), 1.0) + + @property + def time_per_iteration(self): + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self): + if self.length_known and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self): + if self.eta_known: + t = self.eta + 1 + seconds = t % 60 + t /= 60 + minutes = t % 60 + t /= 60 + hours = t % 24 + t /= 24 + if t > 0: + days = t + return '%dd %02d:%02d:%02d' % (days, hours, minutes, seconds) + else: + return '%02d:%02d:%02d' % (hours, minutes, seconds) + return '' + + def format_pos(self): + pos = str(self.pos) + if self.length_known: + pos += '/%s' % self.length + return pos + + def format_pct(self): + return ('% 4d%%' % int(self.pct * 100))[1:] + + def format_progress_line(self): + show_percent = self.show_percent + + info_bits = [] + if self.length_known: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + if show_percent is None: + show_percent = not self.show_pos + else: + if self.finished: + bar = self.fill_char * self.width + else: + bar = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + bar[int((math.cos(self.pos * self.time_per_iteration) + / 2.0 + 0.5) * self.width)] = self.fill_char + bar = ''.join(bar) + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return (self.bar_template % { + 'label': self.label, + 'bar': bar, + 'info': self.info_sep.join(info_bits) + }).rstrip() + + def render_progress(self): + from .termui import get_terminal_size + nl = False + + if self.is_hidden: + buf = [self.label] + nl = True + else: + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, get_terminal_size()[0] - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(' ' * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + buf.append(line) + + buf.append(' ' * (clear_width - line_len)) + line = ''.join(buf) + + # Render the line only if it changed. + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=nl) + self.file.flush() + + def make_step(self, n_steps): + self.pos += n_steps + if self.length_known and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + self.avg = self.avg[-6:] + [-(self.start - time.time()) / (self.pos)] + + self.eta_known = self.length_known + + def update(self, n_steps): + self.make_step(n_steps) + self.render_progress() + + def finish(self): + self.eta_known = 0 + self.current_item = None + self.finished = True + + def next(self): + if self.is_hidden: + return next(self.iter) + try: + rv = next(self.iter) + self.current_item = rv + except StopIteration: + self.finish() + self.render_progress() + raise StopIteration() + else: + self.update(1) + return rv + + if not PY2: + __next__ = next + del next + + +def pager(text, color=None): + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, text, color) + pager_cmd = (os.environ.get('PAGER', None) or '').strip() + if pager_cmd: + if WIN: + return _tempfilepager(text, pager_cmd, color) + return _pipepager(text, pager_cmd, color) + if os.environ.get('TERM') in ('dumb', 'emacs'): + return _nullpager(stdout, text, color) + if WIN or sys.platform.startswith('os2'): + return _tempfilepager(text, 'more <', color) + if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: + return _pipepager(text, 'less', color) + + import tempfile + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0: + return _pipepager(text, 'more', color) + return _nullpager(stdout, text, color) + finally: + os.unlink(filename) + + +def _pipepager(text, cmd, color): + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit('/', 1)[-1].split() + if color is None and cmd_detail[0] == 'less': + less_flags = os.environ.get('LESS', '') + ' '.join(cmd_detail[1:]) + if not less_flags: + env['LESS'] = '-R' + color = True + elif 'r' in less_flags or 'R' in less_flags: + color = True + + if not color: + text = strip_ansi(text) + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, + env=env) + encoding = get_best_encoding(c.stdin) + try: + c.stdin.write(text.encode(encoding, 'replace')) + c.stdin.close() + except (IOError, KeyboardInterrupt): + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager(text, cmd, color): + """Page through text by invoking a program on a temporary file.""" + import tempfile + filename = tempfile.mktemp() + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, 'wb')[0] as f: + f.write(text.encode(encoding)) + try: + os.system(cmd + ' "' + filename + '"') + finally: + os.unlink(filename) + + +def _nullpager(stream, text, color): + """Simply print unformatted text. This is the ultimate fallback.""" + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor(object): + + def __init__(self, editor=None, env=None, require_save=True, + extension='.txt'): + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self): + if self.editor is not None: + return self.editor + for key in 'VISUAL', 'EDITOR': + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return 'notepad' + for editor in 'vim', 'nano': + if os.system('which %s >/dev/null 2>&1' % editor) == 0: + return editor + return 'vi' + + def edit_file(self, filename): + import subprocess + editor = self.get_editor() + if self.env: + environ = os.environ.copy() + environ.update(self.env) + else: + environ = None + try: + c = subprocess.Popen('%s "%s"' % (editor, filename), + env=environ, shell=True) + exit_code = c.wait() + if exit_code != 0: + raise ClickException('%s: Editing failed!' % editor) + except OSError as e: + raise ClickException('%s: Editing failed: %s' % (editor, e)) + + def edit(self, text): + import tempfile + + text = text or '' + if text and not text.endswith('\n'): + text += '\n' + + fd, name = tempfile.mkstemp(prefix='editor-', suffix=self.extension) + try: + if WIN: + encoding = 'utf-8-sig' + text = text.replace('\n', '\r\n') + else: + encoding = 'utf-8' + text = text.encode(encoding) + + f = os.fdopen(fd, 'wb') + f.write(text) + f.close() + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save \ + and os.path.getmtime(name) == timestamp: + return None + + f = open(name, 'rb') + try: + rv = f.read() + finally: + f.close() + return rv.decode('utf-8-sig').replace('\r\n', '\n') + finally: + os.unlink(name) + + +def open_url(url, wait=False, locate=False): + import subprocess + + def _unquote_file(url): + try: + import urllib + except ImportError: + import urllib + if url.startswith('file://'): + url = urllib.unquote(url[7:]) + return url + + if sys.platform == 'darwin': + args = ['open'] + if wait: + args.append('-W') + if locate: + args.append('-R') + args.append(_unquote_file(url)) + null = open('/dev/null', 'w') + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = 'explorer /select,"%s"' % _unquote_file( + url.replace('"', '')) + else: + args = 'start %s "" "%s"' % ( + wait and '/WAIT' or '', url.replace('"', '')) + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or '.' + else: + url = _unquote_file(url) + c = subprocess.Popen(['xdg-open', url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(('http://', 'https://')) and not locate and not wait: + import webbrowser + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch): + if ch == '\x03': + raise KeyboardInterrupt() + if ch == '\x04': + raise EOFError() + + +if WIN: + import msvcrt + + def getchar(echo): + rv = msvcrt.getch() + if echo: + msvcrt.putchar(rv) + _translate_ch_to_exc(rv) + if PY2: + enc = getattr(sys.stdin, 'encoding', None) + if enc is not None: + rv = rv.decode(enc, 'replace') + else: + rv = rv.decode('cp1252', 'replace') + return rv +else: + import tty + import termios + + def getchar(echo): + if not isatty(sys.stdin): + f = open('/dev/tty') + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + try: + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(fd) + ch = os.read(fd, 32) + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + if f is not None: + f.close() + except termios.error: + pass + _translate_ch_to_exc(ch) + return ch.decode(get_best_encoding(sys.stdin), 'replace') diff --git a/venv/lib/python2.7/site-packages/click/_termui_impl.pyc b/venv/lib/python2.7/site-packages/click/_termui_impl.pyc new file mode 100644 index 0000000..2224dac Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/_termui_impl.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/_textwrap.py b/venv/lib/python2.7/site-packages/click/_textwrap.py new file mode 100644 index 0000000..7e77603 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_textwrap.py @@ -0,0 +1,38 @@ +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + + def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent): + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text): + rv = [] + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + if idx > 0: + indent = self.subsequent_indent + rv.append(indent + line) + return '\n'.join(rv) diff --git a/venv/lib/python2.7/site-packages/click/_textwrap.pyc b/venv/lib/python2.7/site-packages/click/_textwrap.pyc new file mode 100644 index 0000000..5b9bdf6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/_textwrap.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/_unicodefun.py b/venv/lib/python2.7/site-packages/click/_unicodefun.py new file mode 100644 index 0000000..9e17a38 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_unicodefun.py @@ -0,0 +1,118 @@ +import os +import sys +import codecs + +from ._compat import PY2 + + +# If someone wants to vendor click, we want to ensure the +# correct package is discovered. Ideally we could use a +# relative import here but unfortunately Python does not +# support that. +click = sys.modules[__name__.rsplit('.', 1)[0]] + + +def _find_unicode_literals_frame(): + import __future__ + frm = sys._getframe(1) + idx = 1 + while frm is not None: + if frm.f_globals.get('__name__', '').startswith('click.'): + frm = frm.f_back + idx += 1 + elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag: + return idx + else: + break + return 0 + + +def _check_for_unicode_literals(): + if not __debug__: + return + if not PY2 or click.disable_unicode_literals_warning: + return + bad_frame = _find_unicode_literals_frame() + if bad_frame <= 0: + return + from warnings import warn + warn(Warning('Click detected the use of the unicode_literals ' + '__future__ import. This is heavily discouraged ' + 'because it can introduce subtle bugs in your ' + 'code. You should instead use explicit u"" literals ' + 'for your unicode strings. For more information see ' + 'http://click.pocoo.org/python3/'), + stacklevel=bad_frame) + + +def _verify_python3_env(): + """Ensures that the environment is good for unicode on Python 3.""" + if PY2: + return + try: + import locale + fs_enc = codecs.lookup(locale.getpreferredencoding()).name + except Exception: + fs_enc = 'ascii' + if fs_enc != 'ascii': + return + + extra = '' + if os.name == 'posix': + import subprocess + rv = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate()[0] + good_locales = set() + has_c_utf8 = False + + # Make sure we're operating on text here. + if isinstance(rv, bytes): + rv = rv.decode('ascii', 'replace') + + for line in rv.splitlines(): + locale = line.strip() + if locale.lower().endswith(('.utf-8', '.utf8')): + good_locales.add(locale) + if locale.lower() in ('c.utf8', 'c.utf-8'): + has_c_utf8 = True + + extra += '\n\n' + if not good_locales: + extra += ( + 'Additional information: on this system no suitable UTF-8\n' + 'locales were discovered. This most likely requires resolving\n' + 'by reconfiguring the locale system.' + ) + elif has_c_utf8: + extra += ( + 'This system supports the C.UTF-8 locale which is recommended.\n' + 'You might be able to resolve your issue by exporting the\n' + 'following environment variables:\n\n' + ' export LC_ALL=C.UTF-8\n' + ' export LANG=C.UTF-8' + ) + else: + extra += ( + 'This system lists a couple of UTF-8 supporting locales that\n' + 'you can pick from. The following suitable locales where\n' + 'discovered: %s' + ) % ', '.join(sorted(good_locales)) + + bad_locale = None + for locale in os.environ.get('LC_ALL'), os.environ.get('LANG'): + if locale and locale.lower().endswith(('.utf-8', '.utf8')): + bad_locale = locale + if locale is not None: + break + if bad_locale is not None: + extra += ( + '\n\nClick discovered that you exported a UTF-8 locale\n' + 'but the locale system could not pick up from it because\n' + 'it does not exist. The exported locale is "%s" but it\n' + 'is not supported' + ) % bad_locale + + raise RuntimeError('Click will abort further execution because Python 3 ' + 'was configured to use ASCII as encoding for the ' + 'environment. Consult http://click.pocoo.org/python3/' + 'for mitigation steps.' + extra) diff --git a/venv/lib/python2.7/site-packages/click/_unicodefun.pyc b/venv/lib/python2.7/site-packages/click/_unicodefun.pyc new file mode 100644 index 0000000..7582ae2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/_unicodefun.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/_winconsole.py b/venv/lib/python2.7/site-packages/click/_winconsole.py new file mode 100644 index 0000000..9aed942 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_winconsole.py @@ -0,0 +1,273 @@ +# -*- coding: utf-8 -*- +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prmopt. + +import io +import os +import sys +import zlib +import time +import ctypes +import msvcrt +from click._compat import _NonClosingTextIOWrapper, text_type, PY2 +from ctypes import byref, POINTER, c_int, c_char, c_char_p, \ + c_void_p, py_object, c_ssize_t, c_ulong, windll, WINFUNCTYPE +try: + from ctypes import pythonapi + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release +except ImportError: + pythonapi = None +from ctypes.wintypes import LPWSTR, LPCWSTR + + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)( + ('GetCommandLineW', windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE( + POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ('CommandLineToArgvW', windll.shell32)) + + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b'\x1a' +MAX_BYTES_WRITTEN = 32767 + + +class Py_buffer(ctypes.Structure): + _fields_ = [ + ('buf', c_void_p), + ('obj', py_object), + ('len', c_ssize_t), + ('itemsize', c_ssize_t), + ('readonly', c_int), + ('ndim', c_int), + ('format', c_char_p), + ('shape', c_ssize_p), + ('strides', c_ssize_p), + ('suboffsets', c_ssize_p), + ('internal', c_void_p) + ] + + if PY2: + _fields_.insert(-1, ('smalltable', c_ssize_t * 2)) + + +# On PyPy we cannot get buffers so our ability to operate here is +# serverly limited. +if pythonapi is None: + get_buffer = None +else: + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + + def __init__(self, handle): + self.handle = handle + + def isatty(self): + io.RawIOBase.isatty(self) + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError('cannot read odd number of bytes from ' + 'UTF-16-LE encoded console') + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW(self.handle, buffer, code_units_to_be_read, + byref(code_units_read), None) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError('Windows error: %s' % GetLastError()) + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return 'ERROR_SUCCESS' + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return 'ERROR_NOT_ENOUGH_MEMORY' + return 'Windows error %s' % errno + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, + MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW(self.handle, buf, code_units_to_be_written, + byref(code_units_written), None) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream(object): + + def __init__(self, text_stream, byte_stream): + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self): + return self.buffer.name + + def write(self, x): + if isinstance(x, text_type): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def __getattr__(self, name): + return getattr(self._text_stream, name) + + def isatty(self): + return self.buffer.isatty() + + def __repr__(self): + return '' % ( + self.name, + self.encoding, + ) + + +def _get_text_stdin(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stdout(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + _WindowsConsoleWriter(STDOUT_HANDLE), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stderr(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + _WindowsConsoleWriter(STDERR_HANDLE), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +if PY2: + def _hash_py_argv(): + return zlib.crc32('\x00'.join(sys.argv[1:])) + + _initial_argv_hash = _hash_py_argv() + + def _get_windows_argv(): + argc = c_int(0) + argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) + argv = [argv_unicode[i] for i in range(0, argc.value)] + + if not hasattr(sys, 'frozen'): + argv = argv[1:] + while len(argv) > 0: + arg = argv[0] + if not arg.startswith('-') or arg == '-': + break + argv = argv[1:] + if arg.startswith(('-c', '-m')): + break + + return argv[1:] + + +_stream_factories = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _get_windows_console_stream(f, encoding, errors): + if get_buffer is not None and \ + encoding in ('utf-16-le', None) \ + and errors in ('strict', None) and \ + hasattr(f, 'isatty') and f.isatty(): + func = _stream_factories.get(f.fileno()) + if func is not None: + if not PY2: + f = getattr(f, 'buffer') + if f is None: + return None + else: + # If we are on Python 2 we need to set the stream that we + # deal with to binary mode as otherwise the exercise if a + # bit moot. The same problems apply as for + # get_binary_stdin and friends from _compat. + msvcrt.setmode(f.fileno(), os.O_BINARY) + return func(f) diff --git a/venv/lib/python2.7/site-packages/click/_winconsole.pyc b/venv/lib/python2.7/site-packages/click/_winconsole.pyc new file mode 100644 index 0000000..fcc4861 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/_winconsole.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/core.py b/venv/lib/python2.7/site-packages/click/core.py new file mode 100644 index 0000000..7456451 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/core.py @@ -0,0 +1,1744 @@ +import errno +import os +import sys +from contextlib import contextmanager +from itertools import repeat +from functools import update_wrapper + +from .types import convert_type, IntRange, BOOL +from .utils import make_str, make_default_short_help, echo, get_os_args +from .exceptions import ClickException, UsageError, BadParameter, Abort, \ + MissingParameter +from .termui import prompt, confirm +from .formatting import HelpFormatter, join_options +from .parser import OptionParser, split_opt +from .globals import push_context, pop_context + +from ._compat import PY2, isidentifier, iteritems +from ._unicodefun import _check_for_unicode_literals, _verify_python3_env + + +_missing = object() + + +SUBCOMMAND_METAVAR = 'COMMAND [ARGS]...' +SUBCOMMANDS_METAVAR = 'COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...' + + +def _bashcomplete(cmd, prog_name, complete_var=None): + """Internal handler for the bash completion support.""" + if complete_var is None: + complete_var = '_%s_COMPLETE' % (prog_name.replace('-', '_')).upper() + complete_instr = os.environ.get(complete_var) + if not complete_instr: + return + + from ._bashcomplete import bashcomplete + if bashcomplete(cmd, prog_name, complete_var, complete_instr): + sys.exit(1) + + +def _check_multicommand(base_command, cmd_name, cmd, register=False): + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = 'It is not possible to add multi commands as children to ' \ + 'another multi command that is in chain mode' + else: + hint = 'Found a multi command as subcommand to a multi command ' \ + 'that is in chain mode. This is not supported' + raise RuntimeError('%s. Command "%s" is set to chain and "%s" was ' + 'added as subcommand but it in itself is a ' + 'multi command. ("%s" is a %s within a chained ' + '%s named "%s"). This restriction was supposed to ' + 'be lifted in 6.0 but the fix was flawed. This ' + 'will be fixed in Click 7.0' % ( + hint, base_command.name, cmd_name, + cmd_name, cmd.__class__.__name__, + base_command.__class__.__name__, + base_command.name)) + + +def batch(iterable, batch_size): + return list(zip(*repeat(iter(iterable), batch_size))) + + +def invoke_param_callback(callback, ctx, param, value): + code = getattr(callback, '__code__', None) + args = getattr(code, 'co_argcount', 3) + + if args < 3: + # This will become a warning in Click 3.0: + from warnings import warn + warn(Warning('Invoked legacy parameter callback "%s". The new ' + 'signature for such callbacks starting with ' + 'click 2.0 is (ctx, param, value).' + % callback), stacklevel=3) + return callback(ctx, value) + return callback(ctx, param, value) + + +@contextmanager +def augment_usage_errors(ctx, param=None): + """Context manager that attaches extra information to exceptions that + fly. + """ + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing(invocation_order, declaration_order): + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + def sort_key(item): + try: + idx = invocation_order.index(item) + except ValueError: + idx = float('inf') + return (not item.is_eager, idx) + + return sorted(declaration_order, key=sort_key) + + +class Context(object): + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + .. versionadded:: 2.0 + Added the `resilient_parsing`, `help_option_names`, + `token_normalize_func` parameters. + + .. versionadded:: 3.0 + Added the `allow_extra_args` and `allow_interspersed_args` + parameters. + + .. versionadded:: 4.0 + Added the `color`, `ignore_unknown_options`, and + `max_content_width` parameters. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + """ + + def __init__(self, command, parent=None, info_name=None, obj=None, + auto_envvar_prefix=None, default_map=None, + terminal_width=None, max_content_width=None, + resilient_parsing=False, allow_extra_args=None, + allow_interspersed_args=None, + ignore_unknown_options=None, help_option_names=None, + token_normalize_func=None, color=None): + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: the parsed parameters except if the value is hidden in which + #: case it's not remembered. + self.params = {} + #: the leftover arguments. + self.args = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args = [] + if obj is None and parent is not None: + obj = parent.obj + #: the user object stored. + self.obj = obj + self._meta = getattr(parent, 'meta', {}) + + #: A dictionary (-like object) with defaults for parameters. + if default_map is None \ + and parent is not None \ + and parent.default_map is not None: + default_map = parent.default_map.get(info_name) + self.default_map = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`resultcallback`. + self.invoked_subcommand = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + #: The width of the terminal (None is autodetection). + self.terminal_width = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ['--help'] + + #: The names for the help options. + self.help_option_names = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures. + self.resilient_parsing = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if parent is not None \ + and parent.auto_envvar_prefix is not None and \ + self.info_name is not None: + auto_envvar_prefix = '%s_%s' % (parent.auto_envvar_prefix, + self.info_name.upper()) + else: + self.auto_envvar_prefix = auto_envvar_prefix.upper() + self.auto_envvar_prefix = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color = color + + self._close_callbacks = [] + self._depth = 0 + + def __enter__(self): + self._depth += 1 + push_context(self) + return self + + def __exit__(self, exc_type, exc_value, tb): + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup=True): + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self): + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utiltiies can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = __name__ + '.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self): + """Creates the formatter for the help and usage output.""" + return HelpFormatter(width=self.terminal_width, + max_width=self.max_content_width) + + def call_on_close(self, f): + """This decorator remembers a function as callback that should be + executed when the context tears down. This is most useful to bind + resource handling to the script execution. For instance, file objects + opened by the :class:`File` type will register their close callbacks + here. + + :param f: the function to execute on teardown. + """ + self._close_callbacks.append(f) + return f + + def close(self): + """Invokes all close callbacks.""" + for cb in self._close_callbacks: + cb() + self._close_callbacks = [] + + @property + def command_path(self): + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = '' + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + rv = self.parent.command_path + ' ' + rv + return rv.lstrip() + + def find_root(self): + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type): + """Finds the closest object of a given type.""" + node = self + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + node = node.parent + + def ensure_object(self, object_type): + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + def lookup_default(self, name): + """Looks up the default for a parameter name. This by default + looks into the :attr:`default_map` if available. + """ + if self.default_map is not None: + rv = self.default_map.get(name) + if callable(rv): + rv = rv() + return rv + + def fail(self, message): + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self): + """Aborts the script.""" + raise Abort() + + def exit(self, code=0): + """Exits the application with a given exit code.""" + sys.exit(code) + + def get_usage(self): + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self): + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def invoke(*args, **kwargs): + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + """ + self, callback = args[:2] + ctx = self + + # It's also possible to invoke another command which might or + # might not have a callback. In that case we also fill + # in defaults and make a new context for this command. + if isinstance(callback, Command): + other_cmd = callback + callback = other_cmd.callback + ctx = Context(other_cmd, info_name=other_cmd.name, parent=self) + if callback is None: + raise TypeError('The given command does not have a ' + 'callback that can be invoked.') + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.get_default(ctx) + + args = args[2:] + with augment_usage_errors(self): + with ctx: + return callback(*args, **kwargs) + + def forward(*args, **kwargs): + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + """ + self, cmd = args[:2] + + # It's also possible to invoke another command which might or + # might not have a callback. + if not isinstance(cmd, Command): + raise TypeError('Callback is not a command.') + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, **kwargs) + + +class BaseCommand(object): + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__(self, name, context_settings=None): + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + if context_settings is None: + context_settings = {} + #: an optional dictionary with defaults passed to the context. + self.context_settings = context_settings + + def get_usage(self, ctx): + raise NotImplementedError('Base commands cannot get usage') + + def get_help(self, ctx): + raise NotImplementedError('Base commands cannot get help') + + def make_context(self, info_name, args, parent=None, **extra): + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + :param info_name: the info name for this invokation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it it's + the name of the script. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + """ + for key, value in iteritems(self.context_settings): + if key not in extra: + extra[key] = value + ctx = Context(self, info_name=info_name, parent=parent, **extra) + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx, args): + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError('Base commands do not know how to parse ' + 'arguments.') + + def invoke(self, ctx): + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError('Base commands are not invokable by default') + + def main(self, args=None, prog_name=None, complete_var=None, + standalone_mode=True, **extra): + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + .. versionadded:: 3.0 + Added the `standalone_mode` flag to control the standalone mode. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + """ + # If we are in Python 3, we will verify that the environment is + # sane at this point of reject further execution to avoid a + # broken script. + if not PY2: + _verify_python3_env() + else: + _check_for_unicode_literals() + + if args is None: + args = get_os_args() + else: + args = list(args) + + if prog_name is None: + prog_name = make_str(os.path.basename( + sys.argv and sys.argv[0] or __file__)) + + # Hook for the Bash completion. This only activates if the Bash + # completion is actually enabled, otherwise this is quite a fast + # noop. + _bashcomplete(self, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + ctx.exit() + except (EOFError, KeyboardInterrupt): + echo(file=sys.stderr) + raise Abort() + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except IOError as e: + if e.errno == errno.EPIPE: + sys.exit(1) + else: + raise + except Abort: + if not standalone_mode: + raise + echo('Aborted!', file=sys.stderr) + sys.exit(1) + + def __call__(self, *args, **kwargs): + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + """ + + def __init__(self, name, context_settings=None, callback=None, + params=None, help=None, epilog=None, short_help=None, + options_metavar='[OPTIONS]', add_help_option=True): + BaseCommand.__init__(self, name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + if short_help is None and help: + short_help = make_default_short_help(help) + self.short_help = short_help + self.add_help_option = add_help_option + + def get_usage(self, ctx): + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip('\n') + + def get_params(self, ctx): + rv = self.params + help_option = self.get_help_option(ctx) + if help_option is not None: + rv = rv + [help_option] + return rv + + def format_usage(self, ctx, formatter): + """Writes the usage line into the formatter.""" + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, ' '.join(pieces)) + + def collect_usage_pieces(self, ctx): + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + return rv + + def get_help_option_names(self, ctx): + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return all_names + + def get_help_option(self, ctx): + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + if not help_options or not self.add_help_option: + return + + def show_help(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + return Option(help_options, is_flag=True, + is_eager=True, expose_value=False, + callback=show_help, + help='Show this message and exit.') + + def make_parser(self, ctx): + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + parser.allow_interspersed_args = ctx.allow_interspersed_args + parser.ignore_unknown_options = ctx.ignore_unknown_options + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx): + """Formats the help into a string and returns it. This creates a + formatter and will call into the following formatting methods: + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip('\n') + + def format_help(self, ctx, formatter): + """Writes the help into the formatter if it exists. + + This calls into the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx, formatter): + """Writes the help text to the formatter if it exists.""" + if self.help: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.help) + + def format_options(self, ctx, formatter): + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section('Options'): + formatter.write_dl(opts) + + def format_epilog(self, ctx, formatter): + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.epilog) + + def parse_args(self, ctx, args): + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing( + param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail('Got unexpected extra argument%s (%s)' + % (len(args) != 1 and 's' or '', + ' '.join(map(make_str, args)))) + + ctx.args = args + return args + + def invoke(self, ctx): + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: the result callback to attach to this multi + command. + """ + allow_extra_args = True + allow_interspersed_args = False + + def __init__(self, name=None, invoke_without_command=False, + no_args_is_help=None, subcommand_metavar=None, + chain=False, result_callback=None, **attrs): + Command.__init__(self, name, **attrs) + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + if subcommand_metavar is None: + if chain: + subcommand_metavar = SUBCOMMANDS_METAVAR + else: + subcommand_metavar = SUBCOMMAND_METAVAR + self.subcommand_metavar = subcommand_metavar + self.chain = chain + #: The result callback that is stored. This can be set or + #: overridden with the :func:`resultcallback` decorator. + self.result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError('Multi commands in chain mode cannot ' + 'have optional arguments.') + + def collect_usage_pieces(self, ctx): + rv = Command.collect_usage_pieces(self, ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx, formatter): + Command.format_options(self, ctx, formatter) + self.format_commands(ctx, formatter) + + def resultcallback(self, replace=False): + """Adds a result callback to the chain command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.resultcallback() + def process_result(result, input): + return result + input + + .. versionadded:: 3.0 + + :param replace: if set to `True` an already existing result + callback will be removed. + """ + def decorator(f): + old_callback = self.result_callback + if old_callback is None or replace: + self.result_callback = f + return f + def function(__value, *args, **kwargs): + return f(old_callback(__value, *args, **kwargs), + *args, **kwargs) + self.result_callback = rv = update_wrapper(function, f) + return rv + return decorator + + def format_commands(self, ctx, formatter): + """Extra format methods for multi methods that adds all the commands + after the options. + """ + rows = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + + help = cmd.short_help or '' + rows.append((subcommand, help)) + + if rows: + with formatter.section('Commands'): + formatter.write_dl(rows) + + def parse_args(self, ctx, args): + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = Command.parse_args(self, ctx, args) + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx): + def _process_result(value): + if self.result_callback is not None: + value = ctx.invoke(self.result_callback, value, + **ctx.params) + return value + + if not ctx.protected_args: + # If we are invoked without command the chain flag controls + # how this happens. If we are not in chain mode, the return + # value here is the return value of the command. + # If however we are in chain mode, the return value is the + # return value of the result processor invoked with an empty + # list (which means that no subcommand actually was executed). + if self.invoke_without_command: + if not self.chain: + return Command.invoke(self, ctx) + with ctx: + Command.invoke(self, ctx) + return _process_result([]) + ctx.fail('Missing command.') + + # Fetch args back out + args = ctx.protected_args + ctx.args + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + ctx.invoked_subcommand = cmd_name + Command.invoke(self, ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = args and '*' or None + Command.invoke(self, ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command(self, ctx, args): + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail('No such command "%s".' % original_cmd_name) + + return cmd_name, cmd, args[1:] + + def get_command(self, ctx, cmd_name): + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError() + + def list_commands(self, ctx): + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is the + most common way to implement nesting in Click. + + :param commands: a dictionary of commands. + """ + + def __init__(self, name=None, commands=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: the registered subcommands by their exported names. + self.commands = commands or {} + + def add_command(self, cmd, name=None): + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError('Command has no name.') + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + def command(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + def decorator(f): + cmd = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + return decorator + + def group(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + def decorator(f): + cmd = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + return decorator + + def get_command(self, ctx, cmd_name): + return self.commands.get(cmd_name) + + def list_commands(self, ctx): + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + """ + + def __init__(self, name=None, sources=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: The list of registered multi commands. + self.sources = sources or [] + + def add_source(self, multi_cmd): + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx, cmd_name): + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + return rv + + def list_commands(self, ctx): + rv = set() + for source in self.sources: + rv.update(source.list_commands(ctx)) + return sorted(rv) + + +class Parameter(object): + """A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. In Click 2.0, the old callback format will still work, + but it will raise a warning to give you change to migrate the + code easier. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The later is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: a callback that should be executed after the parameter + was matched. This is called as ``fn(ctx, param, + value)`` and needs to return the value. Before Click + 2.0, the signature was ``(ctx, value)``. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + """ + param_type_name = 'parameter' + + def __init__(self, param_decls=None, type=None, required=False, + default=None, callback=None, nargs=None, metavar=None, + expose_value=True, is_eager=False, envvar=None): + self.name, self.opts, self.secondary_opts = \ + self._parse_decls(param_decls or (), expose_value) + + self.type = convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = False + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + + @property + def human_readable_name(self): + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + metavar = self.type.get_metavar(self) + if metavar is None: + metavar = self.type.name.upper() + if self.nargs != 1: + metavar += '...' + return metavar + + def get_default(self, ctx): + """Given a context variable this calculates the default value.""" + # Otherwise go with the regular default. + if callable(self.default): + rv = self.default() + else: + rv = self.default + return self.type_cast_value(ctx, rv) + + def add_to_parser(self, parser, ctx): + pass + + def consume_value(self, ctx, opts): + value = opts.get(self.name) + if value is None: + value = ctx.lookup_default(self.name) + if value is None: + value = self.value_from_envvar(ctx) + return value + + def type_cast_value(self, ctx, value): + """Given a value this runs it properly through the type system. + This automatically handles things like `nargs` and `multiple` as + well as composite types. + """ + if self.type.is_composite: + if self.nargs <= 1: + raise TypeError('Attempted to invoke composite type ' + 'but nargs has been set to %s. This is ' + 'not supported; nargs needs to be set to ' + 'a fixed value > 1.' % self.nargs) + if self.multiple: + return tuple(self.type(x or (), self, ctx) for x in value or ()) + return self.type(value or (), self, ctx) + + def _convert(value, level): + if level == 0: + return self.type(value, self, ctx) + return tuple(_convert(x, level - 1) for x in value or ()) + return _convert(value, (self.nargs != 1) + bool(self.multiple)) + + def process_value(self, ctx, value): + """Given a value and context this runs the logic to convert the + value as necessary. + """ + # If the value we were given is None we do nothing. This way + # code that calls this can easily figure out if something was + # not provided. Otherwise it would be converted into an empty + # tuple for multiple invocations which is inconvenient. + if value is not None: + return self.type_cast_value(ctx, value) + + def value_is_missing(self, value): + if value is None: + return True + if (self.nargs != 1 or self.multiple) and value == (): + return True + return False + + def full_process_value(self, ctx, value): + value = self.process_value(ctx, value) + + if value is None: + value = self.get_default(ctx) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + return value + + def resolve_envvar_value(self, ctx): + if self.envvar is None: + return + if isinstance(self.envvar, (tuple, list)): + for envvar in self.envvar: + rv = os.environ.get(envvar) + if rv is not None: + return rv + else: + return os.environ.get(self.envvar) + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + return rv + + def handle_parse_result(self, ctx, opts, args): + with augment_usage_errors(ctx, param=self): + value = self.consume_value(ctx, opts) + try: + value = self.full_process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + value = None + if self.callback is not None: + try: + value = invoke_param_callback( + self.callback, ctx, self, value) + except Exception: + if not ctx.resilient_parsing: + raise + + if self.expose_value: + ctx.params[self.name] = value + return value, args + + def get_help_record(self, ctx): + pass + + def get_usage_pieces(self, ctx): + return [] + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: controls if the default value should be shown on the + help page. Normally, defaults are not shown. + :param prompt: if set to `True` or a non empty string then the user will + be prompted for input if not set. If set to `True` the + prompt will be the option name capitalized. + :param confirmation_prompt: if set then the value will need to be confirmed + if it was prompted for. + :param hide_input: if this is `True` then the input on the prompt will be + hidden from the user. This is useful for password + input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + """ + param_type_name = 'option' + + def __init__(self, param_decls=None, show_default=False, + prompt=False, confirmation_prompt=False, + hide_input=False, is_flag=None, flag_value=None, + multiple=False, count=False, allow_from_autoenv=True, + type=None, help=None, **attrs): + default_is_missing = attrs.get('default', _missing) is _missing + Parameter.__init__(self, param_decls, type=type, **attrs) + + if prompt is True: + prompt_text = self.name.replace('_', ' ').capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.hide_input = hide_input + + # Flags + if is_flag is None: + if flag_value is not None: + is_flag = True + else: + is_flag = bool(self.secondary_opts) + if is_flag and default_is_missing: + self.default = False + if flag_value is None: + flag_value = not self.default + self.is_flag = is_flag + self.flag_value = flag_value + if self.is_flag and isinstance(self.flag_value, bool) \ + and type is None: + self.type = BOOL + self.is_bool_flag = True + else: + self.is_bool_flag = False + + # Counting + self.count = count + if count: + if type is None: + self.type = IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.multiple = multiple + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + + # Sanity check for stuff we don't support + if __debug__: + if self.nargs < 0: + raise TypeError('Options cannot have nargs < 0') + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError('Cannot prompt for flags that are not bools.') + if not self.is_bool_flag and self.secondary_opts: + raise TypeError('Got secondary option for non boolean flag.') + if self.is_bool_flag and self.hide_input \ + and self.prompt is not None: + raise TypeError('Hidden input does not work with boolean ' + 'flag prompts.') + if self.count: + if self.multiple: + raise TypeError('Options cannot be multiple and count ' + 'at the same time.') + elif self.is_flag: + raise TypeError('Options cannot be count and flags at ' + 'the same time.') + + def _parse_decls(self, decls, expose_value): + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if isidentifier(decl): + if name is not None: + raise TypeError('Name defined twice') + name = decl + else: + split_char = decl[:1] == '/' and ';' or '/' + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: len(x[0])) + name = possible_names[-1][1].replace('-', '_').lower() + if not isidentifier(name): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError('Could not determine name for option') + + if not opts and not secondary_opts: + raise TypeError('No options defined but a name was passed (%s). ' + 'Did you mean to declare an argument instead ' + 'of an option?' % name) + + return name, opts, secondary_opts + + def add_to_parser(self, parser, ctx): + kwargs = { + 'dest': self.name, + 'nargs': self.nargs, + 'obj': self, + } + + if self.multiple: + action = 'append' + elif self.count: + action = 'count' + else: + action = 'store' + + if self.is_flag: + kwargs.pop('nargs', None) + if self.is_bool_flag and self.secondary_opts: + parser.add_option(self.opts, action=action + '_const', + const=True, **kwargs) + parser.add_option(self.secondary_opts, action=action + + '_const', const=False, **kwargs) + else: + parser.add_option(self.opts, action=action + '_const', + const=self.flag_value, + **kwargs) + else: + kwargs['action'] = action + parser.add_option(self.opts, **kwargs) + + def get_help_record(self, ctx): + any_prefix_is_slash = [] + + def _write_opts(opts): + rv, any_slashes = join_options(opts) + if any_slashes: + any_prefix_is_slash[:] = [True] + if not self.is_flag and not self.count: + rv += ' ' + self.make_metavar() + return rv + + rv = [_write_opts(self.opts)] + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or '' + extra = [] + if self.default is not None and self.show_default: + extra.append('default: %s' % ( + ', '.join('%s' % d for d in self.default) + if isinstance(self.default, (list, tuple)) + else self.default, )) + if self.required: + extra.append('required') + if extra: + help = '%s[%s]' % (help and help + ' ' or '', '; '.join(extra)) + + return ((any_prefix_is_slash and '; ' or ' / ').join(rv), help) + + def get_default(self, ctx): + # If we're a non boolean flag out default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return param.flag_value + return None + return Parameter.get_default(self, ctx) + + def prompt_for_value(self, ctx): + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt(self.prompt, default=default, + hide_input=self.hide_input, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x)) + + def resolve_envvar_value(self, ctx): + rv = Parameter.resolve_envvar_value(self, ctx) + if rv is not None: + return rv + if self.allow_from_autoenv and \ + ctx.auto_envvar_prefix is not None: + envvar = '%s_%s' % (ctx.auto_envvar_prefix, self.name.upper()) + return os.environ.get(envvar) + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is None: + return None + value_depth = (self.nargs != 1) + bool(self.multiple) + if value_depth > 0 and rv is not None: + rv = self.type.split_envvar_value(rv) + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + return rv + + def full_process_value(self, ctx, value): + if value is None and self.prompt is not None \ + and not ctx.resilient_parsing: + return self.prompt_for_value(ctx) + return Parameter.full_process_value(self, ctx, value) + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the parameter constructor. + """ + param_type_name = 'argument' + + def __init__(self, param_decls, required=None, **attrs): + if required is None: + if attrs.get('default') is not None: + required = False + else: + required = attrs.get('nargs', 1) > 0 + Parameter.__init__(self, param_decls, required=required, **attrs) + if self.default is not None and self.nargs < 0: + raise TypeError('nargs=-1 in combination with a default value ' + 'is not supported.') + + @property + def human_readable_name(self): + if self.metavar is not None: + return self.metavar + return self.name.upper() + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + var = self.name.upper() + if not self.required: + var = '[%s]' % var + if self.nargs != 1: + var += '...' + return var + + def _parse_decls(self, decls, expose_value): + if not decls: + if not expose_value: + return None, [], [] + raise TypeError('Could not determine name for argument') + if len(decls) == 1: + name = arg = decls[0] + name = name.replace('-', '_').lower() + elif len(decls) == 2: + name, arg = decls + else: + raise TypeError('Arguments take exactly one or two ' + 'parameter declarations, got %d' % len(decls)) + return name, [arg], [] + + def get_usage_pieces(self, ctx): + return [self.make_metavar()] + + def add_to_parser(self, parser, ctx): + parser.add_argument(dest=self.name, nargs=self.nargs, + obj=self) + + +# Circular dependency between decorators and core +from .decorators import command, group diff --git a/venv/lib/python2.7/site-packages/click/core.pyc b/venv/lib/python2.7/site-packages/click/core.pyc new file mode 100644 index 0000000..8c3c802 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/core.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/decorators.py b/venv/lib/python2.7/site-packages/click/decorators.py new file mode 100644 index 0000000..9893452 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/decorators.py @@ -0,0 +1,304 @@ +import sys +import inspect + +from functools import update_wrapper + +from ._compat import iteritems +from ._unicodefun import _check_for_unicode_literals +from .utils import echo +from .globals import get_current_context + + +def pass_context(f): + """Marks a callback as wanting to receive the current context + object as first argument. + """ + def new_func(*args, **kwargs): + return f(get_current_context(), *args, **kwargs) + return update_wrapper(new_func, f) + + +def pass_obj(f): + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + def new_func(*args, **kwargs): + return f(get_current_context().obj, *args, **kwargs) + return update_wrapper(new_func, f) + + +def make_pass_decorator(object_type, ensure=False): + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + def decorator(f): + def new_func(*args, **kwargs): + ctx = get_current_context() + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + if obj is None: + raise RuntimeError('Managed to invoke callback without a ' + 'context object of type %r existing' + % object_type.__name__) + return ctx.invoke(f, obj, *args[1:], **kwargs) + return update_wrapper(new_func, f) + return decorator + + +def _make_command(f, name, attrs, cls): + if isinstance(f, Command): + raise TypeError('Attempted to convert a callback into a ' + 'command twice.') + try: + params = f.__click_params__ + params.reverse() + del f.__click_params__ + except AttributeError: + params = [] + help = attrs.get('help') + if help is None: + help = inspect.getdoc(f) + if isinstance(help, bytes): + help = help.decode('utf-8') + else: + help = inspect.cleandoc(help) + attrs['help'] = help + _check_for_unicode_literals() + return cls(name=name or f.__name__.lower(), + callback=f, params=params, **attrs) + + +def command(name=None, cls=None, **attrs): + """Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function. If you + want to change that, you can pass the intended name as the first + argument. + + All keyword arguments are forwarded to the underlying command class. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + """ + if cls is None: + cls = Command + def decorator(f): + cmd = _make_command(f, name, attrs, cls) + cmd.__doc__ = f.__doc__ + return cmd + return decorator + + +def group(name=None, **attrs): + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + """ + attrs.setdefault('cls', Group) + return command(name, **attrs) + + +def _param_memo(f, param): + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, '__click_params__'): + f.__click_params__ = [] + f.__click_params__.append(param) + + +def argument(*param_decls, **attrs): + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + """ + def decorator(f): + ArgumentClass = attrs.pop('cls', Argument) + _param_memo(f, ArgumentClass(param_decls, **attrs)) + return f + return decorator + + +def option(*param_decls, **attrs): + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + def decorator(f): + if 'help' in attrs: + attrs['help'] = inspect.cleandoc(attrs['help']) + OptionClass = attrs.pop('cls', Option) + _param_memo(f, OptionClass(param_decls, **attrs)) + return f + return decorator + + +def confirmation_option(*param_decls, **attrs): + """Shortcut for confirmation prompts that can be ignored by passing + ``--yes`` as parameter. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + def callback(ctx, param, value): + if not value: + ctx.abort() + + @click.command() + @click.option('--yes', is_flag=True, callback=callback, + expose_value=False, prompt='Do you want to continue?') + def dropdb(): + pass + """ + def decorator(f): + def callback(ctx, param, value): + if not value: + ctx.abort() + attrs.setdefault('is_flag', True) + attrs.setdefault('callback', callback) + attrs.setdefault('expose_value', False) + attrs.setdefault('prompt', 'Do you want to continue?') + attrs.setdefault('help', 'Confirm the action without prompting.') + return option(*(param_decls or ('--yes',)), **attrs)(f) + return decorator + + +def password_option(*param_decls, **attrs): + """Shortcut for password prompts. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + @click.command() + @click.option('--password', prompt=True, confirmation_prompt=True, + hide_input=True) + def changeadmin(password): + pass + """ + def decorator(f): + attrs.setdefault('prompt', True) + attrs.setdefault('confirmation_prompt', True) + attrs.setdefault('hide_input', True) + return option(*(param_decls or ('--password',)), **attrs)(f) + return decorator + + +def version_option(version=None, *param_decls, **attrs): + """Adds a ``--version`` option which immediately ends the program + printing out the version number. This is implemented as an eager + option that prints the version and exits the program in the callback. + + :param version: the version number to show. If not provided Click + attempts an auto discovery via setuptools. + :param prog_name: the name of the program (defaults to autodetection) + :param message: custom message to show instead of the default + (``'%(prog)s, version %(version)s'``) + :param others: everything else is forwarded to :func:`option`. + """ + if version is None: + module = sys._getframe(1).f_globals.get('__name__') + def decorator(f): + prog_name = attrs.pop('prog_name', None) + message = attrs.pop('message', '%(prog)s, version %(version)s') + + def callback(ctx, param, value): + if not value or ctx.resilient_parsing: + return + prog = prog_name + if prog is None: + prog = ctx.find_root().info_name + ver = version + if ver is None: + try: + import pkg_resources + except ImportError: + pass + else: + for dist in pkg_resources.working_set: + scripts = dist.get_entry_map().get('console_scripts') or {} + for script_name, entry_point in iteritems(scripts): + if entry_point.module_name == module: + ver = dist.version + break + if ver is None: + raise RuntimeError('Could not determine version') + echo(message % { + 'prog': prog, + 'version': ver, + }, color=ctx.color) + ctx.exit() + + attrs.setdefault('is_flag', True) + attrs.setdefault('expose_value', False) + attrs.setdefault('is_eager', True) + attrs.setdefault('help', 'Show the version and exit.') + attrs['callback'] = callback + return option(*(param_decls or ('--version',)), **attrs)(f) + return decorator + + +def help_option(*param_decls, **attrs): + """Adds a ``--help`` option which immediately ends the program + printing out the help page. This is usually unnecessary to add as + this is added by default to all commands unless suppressed. + + Like :func:`version_option`, this is implemented as eager option that + prints in the callback and exits. + + All arguments are forwarded to :func:`option`. + """ + def decorator(f): + def callback(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + attrs.setdefault('is_flag', True) + attrs.setdefault('expose_value', False) + attrs.setdefault('help', 'Show this message and exit.') + attrs.setdefault('is_eager', True) + attrs['callback'] = callback + return option(*(param_decls or ('--help',)), **attrs)(f) + return decorator + + +# Circular dependencies between core and decorators +from .core import Command, Group, Argument, Option diff --git a/venv/lib/python2.7/site-packages/click/decorators.pyc b/venv/lib/python2.7/site-packages/click/decorators.pyc new file mode 100644 index 0000000..6590964 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/decorators.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/exceptions.py b/venv/lib/python2.7/site-packages/click/exceptions.py new file mode 100644 index 0000000..74a4542 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/exceptions.py @@ -0,0 +1,201 @@ +from ._compat import PY2, filename_to_ui, get_text_stderr +from .utils import echo + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception + exit_code = 1 + + def __init__(self, message): + if PY2: + if message is not None: + message = message.encode('utf-8') + Exception.__init__(self, message) + self.message = message + + def format_message(self): + return self.message + + def show(self, file=None): + if file is None: + file = get_text_stderr() + echo('Error: %s' % self.format_message(), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + exit_code = 2 + + def __init__(self, message, ctx=None): + ClickException.__init__(self, message) + self.ctx = ctx + + def show(self, file=None): + if file is None: + file = get_text_stderr() + color = None + if self.ctx is not None: + color = self.ctx.color + echo(self.ctx.get_usage() + '\n', file=file, color=color) + echo('Error: %s' % self.format_message(), file=file, color=color) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__(self, message, ctx=None, param=None, + param_hint=None): + UsageError.__init__(self, message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.opts or [self.param.human_readable_name] + else: + return 'Invalid value: %s' % self.message + if isinstance(param_hint, (tuple, list)): + param_hint = ' / '.join('"%s"' % x for x in param_hint) + return 'Invalid value for %s: %s' % (param_hint, self.message) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__(self, message=None, ctx=None, param=None, + param_hint=None, param_type=None): + BadParameter.__init__(self, message, ctx, param, param_hint) + self.param_type = param_type + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.opts or [self.param.human_readable_name] + else: + param_hint = None + if isinstance(param_hint, (tuple, list)): + param_hint = ' / '.join('"%s"' % x for x in param_hint) + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += '. ' + msg_extra + else: + msg = msg_extra + + return 'Missing %s%s%s%s' % ( + param_type, + param_hint and ' %s' % param_hint or '', + msg and '. ' or '.', + msg or '', + ) + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__(self, option_name, message=None, possibilities=None, + ctx=None): + if message is None: + message = 'no such option: %s' % option_name + UsageError.__init__(self, message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self): + bits = [self.message] + if self.possibilities: + if len(self.possibilities) == 1: + bits.append('Did you mean %s?' % self.possibilities[0]) + else: + possibilities = sorted(self.possibilities) + bits.append('(Possible options: %s)' % ', '.join(possibilities)) + return ' '.join(bits) + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + """ + + def __init__(self, message, ctx=None): + UsageError.__init__(self, message, ctx) + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + def __init__(self, message, ctx=None): + UsageError.__init__(self, message, ctx) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename, hint=None): + ui_filename = filename_to_ui(filename) + if hint is None: + hint = 'unknown error' + ClickException.__init__(self, hint) + self.ui_filename = ui_filename + self.filename = filename + + def format_message(self): + return 'Could not open file %s: %s' % (self.ui_filename, self.message) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" diff --git a/venv/lib/python2.7/site-packages/click/exceptions.pyc b/venv/lib/python2.7/site-packages/click/exceptions.pyc new file mode 100644 index 0000000..e3cdca8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/exceptions.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/formatting.py b/venv/lib/python2.7/site-packages/click/formatting.py new file mode 100644 index 0000000..a3d6a4d --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/formatting.py @@ -0,0 +1,256 @@ +from contextlib import contextmanager +from .termui import get_terminal_size +from .parser import split_opt +from ._compat import term_len + + +# Can force a width. This is used by the test system +FORCED_WIDTH = None + + +def measure_table(rows): + widths = {} + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows(rows, col_count): + for row in rows: + row = tuple(row) + yield row + ('',) * (col_count - len(row)) + + +def wrap_text(text, width=78, initial_indent='', subsequent_indent='', + preserve_paragraphs=False): + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + text = text.expandtabs() + wrapper = TextWrapper(width, initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False) + if not preserve_paragraphs: + return wrapper.fill(text) + + p = [] + buf = [] + indent = None + + def _flush_par(): + if not buf: + return + if buf[0].strip() == '\b': + p.append((indent or 0, True, '\n'.join(buf[1:]))) + else: + p.append((indent or 0, False, ' '.join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(' ' * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return '\n\n'.join(rv) + + +class HelpFormatter(object): + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__(self, indent_increment=2, width=None, max_width=None): + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(get_terminal_size()[0], max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer = [] + + def write(self, string): + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self): + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self): + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog, args='', prefix='Usage: '): + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: the prefix for the first line. + """ + usage_prefix = '%*s%s ' % (self.current_indent, prefix, prog) + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = ' ' * term_len(usage_prefix) + self.write(wrap_text(args, text_width, + initial_indent=usage_prefix, + subsequent_indent=indent)) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write('\n') + indent = ' ' * (max(self.current_indent, term_len(prefix)) + 4) + self.write(wrap_text(args, text_width, + initial_indent=indent, + subsequent_indent=indent)) + + self.write('\n') + + def write_heading(self, heading): + """Writes a heading into the buffer.""" + self.write('%*s%s:\n' % (self.current_indent, '', heading)) + + def write_paragraph(self): + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write('\n') + + def write_text(self, text): + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + text_width = max(self.width - self.current_indent, 11) + indent = ' ' * self.current_indent + self.write(wrap_text(text, text_width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True)) + self.write('\n') + + def write_dl(self, rows, col_max=30, col_spacing=2): + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError('Expected two columns for definition list') + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write('%*s%s' % (self.current_indent, '', first)) + if not second: + self.write('\n') + continue + if term_len(first) <= first_col - col_spacing: + self.write(' ' * (first_col - term_len(first))) + else: + self.write('\n') + self.write(' ' * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + lines = iter(wrap_text(second, text_width).splitlines()) + if lines: + self.write(next(lines) + '\n') + for line in lines: + self.write('%*s%s\n' % ( + first_col + self.current_indent, '', line)) + else: + self.write('\n') + + @contextmanager + def section(self, name): + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self): + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self): + """Returns the buffer contents.""" + return ''.join(self.buffer) + + +def join_options(options): + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + for opt in options: + prefix = split_opt(opt)[0] + if prefix == '/': + any_prefix_is_slash = True + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + + rv = ', '.join(x[1] for x in rv) + return rv, any_prefix_is_slash diff --git a/venv/lib/python2.7/site-packages/click/formatting.pyc b/venv/lib/python2.7/site-packages/click/formatting.pyc new file mode 100644 index 0000000..b107def Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/formatting.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/globals.py b/venv/lib/python2.7/site-packages/click/globals.py new file mode 100644 index 0000000..14338e6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/globals.py @@ -0,0 +1,48 @@ +from threading import local + + +_local = local() + + +def get_current_context(silent=False): + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing it's behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: is set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return getattr(_local, 'stack')[-1] + except (AttributeError, IndexError): + if not silent: + raise RuntimeError('There is no active click context.') + + +def push_context(ctx): + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault('stack', []).append(ctx) + + +def pop_context(): + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color=None): + """"Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + ctx = get_current_context(silent=True) + if ctx is not None: + return ctx.color diff --git a/venv/lib/python2.7/site-packages/click/globals.pyc b/venv/lib/python2.7/site-packages/click/globals.pyc new file mode 100644 index 0000000..e93568c Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/globals.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/parser.py b/venv/lib/python2.7/site-packages/click/parser.py new file mode 100644 index 0000000..9775c9f --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/parser.py @@ -0,0 +1,426 @@ +# -*- coding: utf-8 -*- +""" + click.parser + ~~~~~~~~~~~~ + + This module started out as largely a copy paste from the stdlib's + optparse module with the features removed that we do not need from + optparse because we implement them in Click on a higher level (for + instance type handling, help formatting and a lot more). + + The plan is to remove more and more from here over time. + + The reason this is a different module and not optparse from the stdlib + is that there are differences in 2.x and 3.x about the error messages + generated and optparse in the stdlib uses gettext for no good reason + and might cause us issues. +""" +import re +from collections import deque +from .exceptions import UsageError, NoSuchOption, BadOptionUsage, \ + BadArgumentUsage + + +def _unpack_args(args, nargs_spec): + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv = [] + spos = None + + def _fetch(c): + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError('Cannot have two nargs < 0') + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1:] = reversed(rv[spos + 1:]) + + return tuple(rv), list(args) + + +def _error_opt_args(nargs, opt): + if nargs == 1: + raise BadOptionUsage('%s option requires an argument' % opt) + raise BadOptionUsage('%s option requires %d arguments' % (opt, nargs)) + + +def split_opt(opt): + first = opt[:1] + if first.isalnum(): + return '', opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt, ctx): + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return prefix + ctx.token_normalize_func(opt) + + +def split_arg_string(string): + """Given an argument string this attempts to split it into small parts.""" + rv = [] + for match in re.finditer(r"('([^'\\]*(?:\\.[^'\\]*)*)'" + r'|"([^"\\]*(?:\\.[^"\\]*)*)"' + r'|\S+)\s*', string, re.S): + arg = match.group().strip() + if arg[:1] == arg[-1:] and arg[:1] in '"\'': + arg = arg[1:-1].encode('ascii', 'backslashreplace') \ + .decode('unicode-escape') + try: + arg = type(string)(arg) + except UnicodeError: + pass + rv.append(arg) + return rv + + +class Option(object): + + def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None): + self._short_opts = [] + self._long_opts = [] + self.prefixes = set() + + for opt in opts: + prefix, value = split_opt(opt) + if not prefix: + raise ValueError('Invalid start character for option (%s)' + % opt) + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = 'store' + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self): + return self.action in ('store', 'append') + + def process(self, value, state): + if self.action == 'store': + state.opts[self.dest] = value + elif self.action == 'store_const': + state.opts[self.dest] = self.const + elif self.action == 'append': + state.opts.setdefault(self.dest, []).append(value) + elif self.action == 'append_const': + state.opts.setdefault(self.dest, []).append(self.const) + elif self.action == 'count': + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 + else: + raise ValueError('unknown action %r' % self.action) + state.order.append(self.obj) + + +class Argument(object): + + def __init__(self, dest, nargs=1, obj=None): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process(self, value, state): + if self.nargs > 1: + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage('argument %s takes %d values' + % (self.dest, self.nargs)) + state.opts[self.dest] = value + state.order.append(self.obj) + + +class ParsingState(object): + + def __init__(self, rargs): + self.opts = {} + self.largs = [] + self.rargs = rargs + self.order = [] + + +class OptionParser(object): + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx=None): + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options = False + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + self._short_opt = {} + self._long_opt = {} + self._opt_prefixes = set(['-', '--']) + self._args = [] + + def add_option(self, opts, dest, action=None, nargs=1, const=None, + obj=None): + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``appnd_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(opts, dest, action=action, nargs=nargs, + const=const, obj=obj) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, dest, nargs=1, obj=None): + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + self._args.append(Argument(dest=dest, nargs=nargs, obj=obj)) + + def parse_args(self, args): + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state): + pargs, args = _unpack_args(state.largs + state.rargs, + [x.nargs for x in self._args]) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state): + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == '--': + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt(self, opt, explicit_value, state): + if opt not in self._long_opt: + possibilities = [word for word in self._long_opt + if word.startswith(opt)] + raise NoSuchOption(opt, possibilities=possibilities) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + elif explicit_value is not None: + raise BadOptionUsage('%s option does not take a value' % opt) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg, state): + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(prefix + ch, self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we re-combinate the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(prefix + ''.join(unknown_options)) + + def _process_opts(self, arg, state): + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if '=' in arg: + long_opt, explicit_value = arg.split('=', 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + return self._match_short_opt(arg, state) + if not self.ignore_unknown_options: + raise + state.largs.append(arg) diff --git a/venv/lib/python2.7/site-packages/click/parser.pyc b/venv/lib/python2.7/site-packages/click/parser.pyc new file mode 100644 index 0000000..e8ea595 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/parser.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/termui.py b/venv/lib/python2.7/site-packages/click/termui.py new file mode 100644 index 0000000..d9fba52 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/termui.py @@ -0,0 +1,539 @@ +import os +import sys +import struct + +from ._compat import raw_input, text_type, string_types, \ + isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN +from .utils import echo +from .exceptions import Abort, UsageError +from .types import convert_type +from .globals import resolve_color_default + + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func = raw_input + +_ansi_colors = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', + 'cyan', 'white', 'reset') +_ansi_reset_all = '\033[0m' + + +def hidden_prompt_func(prompt): + import getpass + return getpass.getpass(prompt) + + +def _build_prompt(text, suffix, show_default=False, default=None): + prompt = text + if default is not None and show_default: + prompt = '%s [%s]' % (prompt, default) + return prompt + suffix + + +def prompt(text, default=None, hide_input=False, + confirmation_prompt=False, type=None, + value_proc=None, prompt_suffix=': ', + show_default=True, err=False): + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending a interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: asks for confirmation for the value. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + result = None + + def prompt_func(text): + f = hide_input and hidden_prompt_func or visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text, nl=False, err=err) + return f('') + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt(text, prompt_suffix, show_default, default) + + while 1: + while 1: + value = prompt_func(prompt) + if value: + break + # If a default is set and used, then the confirmation + # prompt is always skipped because that's the only thing + # that really makes sense. + elif default is not None: + return default + try: + result = value_proc(value) + except UsageError as e: + echo('Error: %s' % e.message, err=err) + continue + if not confirmation_prompt: + return result + while 1: + value2 = prompt_func('Repeat for confirmation: ') + if value2: + break + if value == value2: + return result + echo('Error: the two entered values do not match', err=err) + + +def confirm(text, default=False, abort=False, prompt_suffix=': ', + show_default=True, err=False): + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the question to ask. + :param default: the default for the prompt. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + prompt = _build_prompt(text, prompt_suffix, show_default, + default and 'Y/n' or 'y/N') + while 1: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt, nl=False, err=err) + value = visible_prompt_func('').lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() + if value in ('y', 'yes'): + rv = True + elif value in ('n', 'no'): + rv = False + elif value == '': + rv = default + else: + echo('Error: invalid input', err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def get_terminal_size(): + """Returns the current size of the terminal as tuple in the form + ``(width, height)`` in columns and rows. + """ + # If shutil has get_terminal_size() (Python 3.3 and later) use that + if sys.version_info >= (3, 3): + import shutil + shutil_get_terminal_size = getattr(shutil, 'get_terminal_size', None) + if shutil_get_terminal_size: + sz = shutil_get_terminal_size() + return sz.columns, sz.lines + + if get_winterm_size is not None: + return get_winterm_size() + + def ioctl_gwinsz(fd): + try: + import fcntl + import termios + cr = struct.unpack( + 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) + except Exception: + return + return cr + + cr = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + try: + cr = ioctl_gwinsz(fd) + finally: + os.close(fd) + except Exception: + pass + if not cr or not cr[0] or not cr[1]: + cr = (os.environ.get('LINES', 25), + os.environ.get('COLUMNS', DEFAULT_COLUMNS)) + return int(cr[1]), int(cr[0]) + + +def echo_via_pager(text, color=None): + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text: the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + if not isinstance(text, string_types): + text = text_type(text) + from ._termui_impl import pager + return pager(text + '\n', color) + + +def progressbar(iterable=None, length=None, label=None, show_eta=True, + show_percent=None, show_pos=False, + item_show_func=None, fill_char='#', empty_char='-', + bar_template='%(label)s [%(bar)s] %(info)s', + info_sep=' ', width=36, file=None, color=None): + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already displayed. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `color` parameter. Added a `update` method to the + progressbar object. + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: a function called with the current item which + can return a string to show the current item + next to the progress bar. Note that the current + item can be `None`! + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: the file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + """ + from ._termui_impl import ProgressBar + color = resolve_color_default(color) + return ProgressBar(iterable=iterable, length=length, show_eta=show_eta, + show_percent=show_percent, show_pos=show_pos, + item_show_func=item_show_func, fill_char=fill_char, + empty_char=empty_char, bar_template=bar_template, + info_sep=info_sep, file=file, label=label, + width=width, color=color) + + +def clear(): + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + # If we're on Windows and we don't have colorama available, then we + # clear the screen by shelling out. Otherwise we can use an escape + # sequence. + if WIN: + os.system('cls') + else: + sys.stdout.write('\033[2J\033[1;1H') + + +def style(text, fg=None, bg=None, bold=None, dim=None, underline=None, + blink=None, reverse=None, reset=True): + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``reset`` (reset the color code only) + + .. versionadded:: 2.0 + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + """ + bits = [] + if fg: + try: + bits.append('\033[%dm' % (_ansi_colors.index(fg) + 30)) + except ValueError: + raise TypeError('Unknown color %r' % fg) + if bg: + try: + bits.append('\033[%dm' % (_ansi_colors.index(bg) + 40)) + except ValueError: + raise TypeError('Unknown color %r' % bg) + if bold is not None: + bits.append('\033[%dm' % (1 if bold else 22)) + if dim is not None: + bits.append('\033[%dm' % (2 if dim else 22)) + if underline is not None: + bits.append('\033[%dm' % (4 if underline else 24)) + if blink is not None: + bits.append('\033[%dm' % (5 if blink else 25)) + if reverse is not None: + bits.append('\033[%dm' % (7 if reverse else 27)) + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return ''.join(bits) + + +def unstyle(text): + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho(text, file=None, nl=True, err=False, color=None, **styles): + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + .. versionadded:: 2.0 + """ + return echo(style(text, **styles), file=file, nl=nl, err=err, color=color) + + +def edit(text=None, editor=None, env=None, require_save=True, + extension='.txt', filename=None): + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + editor = Editor(editor=editor, env=env, require_save=require_save, + extension=extension) + if filename is None: + return editor.edit(text) + editor.edit_file(filename) + + +def launch(url, wait=False, locate=False): + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('http://click.pocoo.org/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: waits for the program to stop. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar = None + + +def getchar(echo=False): + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + f = _getchar + if f is None: + from ._termui_impl import getchar as f + return f(echo) + + +def pause(info='Press any key to continue ...', err=False): + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: the info string to print before pausing. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/venv/lib/python2.7/site-packages/click/termui.pyc b/venv/lib/python2.7/site-packages/click/termui.pyc new file mode 100644 index 0000000..9d0fee4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/termui.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/testing.py b/venv/lib/python2.7/site-packages/click/testing.py new file mode 100644 index 0000000..4416c77 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/testing.py @@ -0,0 +1,322 @@ +import os +import sys +import shutil +import tempfile +import contextlib + +from ._compat import iteritems, PY2 + + +# If someone wants to vendor click, we want to ensure the +# correct package is discovered. Ideally we could use a +# relative import here but unfortunately Python does not +# support that. +clickpkg = sys.modules[__name__.rsplit('.', 1)[0]] + + +if PY2: + from cStringIO import StringIO +else: + import io + from ._compat import _find_binary_reader + + +class EchoingStdin(object): + + def __init__(self, input, output): + self._input = input + self._output = output + + def __getattr__(self, x): + return getattr(self._input, x) + + def _echo(self, rv): + self._output.write(rv) + return rv + + def read(self, n=-1): + return self._echo(self._input.read(n)) + + def readline(self, n=-1): + return self._echo(self._input.readline(n)) + + def readlines(self): + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self): + return iter(self._echo(x) for x in self._input) + + def __repr__(self): + return repr(self._input) + + +def make_input_stream(input, charset): + # Is already an input stream. + if hasattr(input, 'read'): + if PY2: + return input + rv = _find_binary_reader(input) + if rv is not None: + return rv + raise TypeError('Could not find binary reader for input stream.') + + if input is None: + input = b'' + elif not isinstance(input, bytes): + input = input.encode(charset) + if PY2: + return StringIO(input) + return io.BytesIO(input) + + +class Result(object): + """Holds the captured result of an invoked CLI script.""" + + def __init__(self, runner, output_bytes, exit_code, exception, + exc_info=None): + #: The runner that created the result + self.runner = runner + #: The output as bytes. + self.output_bytes = output_bytes + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happend if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self): + """The output as unicode string.""" + return self.output_bytes.decode(self.runner.charset, 'replace') \ + .replace('\r\n', '\n') + + def __repr__(self): + return '' % ( + self.exception and repr(self.exception) or 'okay', + ) + + +class CliRunner(object): + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. This is + UTF-8 by default and should not be changed currently as + the reporting to Click only works in Python 2 properly. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + """ + + def __init__(self, charset=None, env=None, echo_stdin=False): + if charset is None: + charset = 'utf-8' + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + + def get_default_prog_name(self, cli): + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or 'root' + + def make_env(self, overrides=None): + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation(self, input=None, env=None, color=False): + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + input = make_input_stream(input, self.charset) + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = clickpkg.formatting.FORCED_WIDTH + clickpkg.formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + if PY2: + sys.stdout = sys.stderr = bytes_output = StringIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + else: + bytes_output = io.BytesIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + input = io.TextIOWrapper(input, encoding=self.charset) + sys.stdout = sys.stderr = io.TextIOWrapper( + bytes_output, encoding=self.charset) + + sys.stdin = input + + def visible_input(prompt=None): + sys.stdout.write(prompt or '') + val = input.readline().rstrip('\r\n') + sys.stdout.write(val + '\n') + sys.stdout.flush() + return val + + def hidden_input(prompt=None): + sys.stdout.write((prompt or '') + '\n') + sys.stdout.flush() + return input.readline().rstrip('\r\n') + + def _getchar(echo): + char = sys.stdin.read(1) + if echo: + sys.stdout.write(char) + sys.stdout.flush() + return char + + default_color = color + def should_strip_ansi(stream=None, color=None): + if color is None: + return not default_color + return not color + + old_visible_prompt_func = clickpkg.termui.visible_prompt_func + old_hidden_prompt_func = clickpkg.termui.hidden_prompt_func + old__getchar_func = clickpkg.termui._getchar + old_should_strip_ansi = clickpkg.utils.should_strip_ansi + clickpkg.termui.visible_prompt_func = visible_input + clickpkg.termui.hidden_prompt_func = hidden_input + clickpkg.termui._getchar = _getchar + clickpkg.utils.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in iteritems(env): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield bytes_output + finally: + for key, value in iteritems(old_env): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + clickpkg.termui.visible_prompt_func = old_visible_prompt_func + clickpkg.termui.hidden_prompt_func = old_hidden_prompt_func + clickpkg.termui._getchar = old__getchar_func + clickpkg.utils.should_strip_ansi = old_should_strip_ansi + clickpkg.formatting.FORCED_WIDTH = old_forced_width + + def invoke(self, cli, args=None, input=None, env=None, + catch_exceptions=True, color=False, **extra): + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + .. versionadded:: 3.0 + The ``catch_exceptions`` parameter was added. + + .. versionchanged:: 3.0 + The result object now has an `exc_info` attribute with the + traceback if available. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param cli: the command to invoke + :param args: the arguments to invoke + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as out: + exception = None + exit_code = 0 + + try: + cli.main(args=args or (), + prog_name=self.get_default_prog_name(cli), **extra) + except SystemExit as e: + if e.code != 0: + exception = e + + exc_info = sys.exc_info() + + exit_code = e.code + if not isinstance(exit_code, int): + sys.stdout.write(str(exit_code)) + sys.stdout.write('\n') + exit_code = 1 + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = -1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + output = out.getvalue() + + return Result(runner=self, + output_bytes=output, + exit_code=exit_code, + exception=exception, + exc_info=exc_info) + + @contextlib.contextmanager + def isolated_filesystem(self): + """A context manager that creates a temporary folder and changes + the current working directory to it for isolated filesystem tests. + """ + cwd = os.getcwd() + t = tempfile.mkdtemp() + os.chdir(t) + try: + yield t + finally: + os.chdir(cwd) + try: + shutil.rmtree(t) + except (OSError, IOError): + pass diff --git a/venv/lib/python2.7/site-packages/click/testing.pyc b/venv/lib/python2.7/site-packages/click/testing.pyc new file mode 100644 index 0000000..919269a Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/testing.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/types.py b/venv/lib/python2.7/site-packages/click/types.py new file mode 100644 index 0000000..3639002 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/types.py @@ -0,0 +1,550 @@ +import os +import stat + +from ._compat import open_stream, text_type, filename_to_ui, \ + get_filesystem_encoding, get_streerror, _get_argv_encoding, PY2 +from .exceptions import BadParameter +from .utils import safecall, LazyFile + + +class ParamType(object): + """Helper for converting values through types. The following is + necessary for a valid type: + + * it needs a name + * it needs to pass through None unchanged + * it needs to convert from a string + * it needs to convert its result type through unchanged + (eg: needs to be idempotent) + * it needs to be able to deal with param and context being `None`. + This can be the case when the object is used with prompt + inputs. + """ + is_composite = False + + #: the descriptive name of this type + name = None + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter = None + + def __call__(self, value, param=None, ctx=None): + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param): + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param): + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert(self, value, param, ctx): + """Converts the value. This is not invoked for values that are + `None` (the missing value). + """ + return value + + def split_envvar_value(self, rv): + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or '').split(self.envvar_list_splitter) + + def fail(self, message, param=None, ctx=None): + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self): + raise NotImplementedError() + + +class FuncParamType(ParamType): + + def __init__(self, func): + self.name = func.__name__ + self.func = func + + def convert(self, value, param, ctx): + try: + return self.func(value) + except ValueError: + try: + value = text_type(value) + except UnicodeError: + value = str(value).decode('utf-8', 'replace') + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = 'text' + + def convert(self, value, param, ctx): + return value + + def __repr__(self): + return 'UNPROCESSED' + + +class StringParamType(ParamType): + name = 'text' + + def convert(self, value, param, ctx): + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = get_filesystem_encoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode('utf-8', 'replace') + return value + return value + + def __repr__(self): + return 'STRING' + + +class Choice(ParamType): + """The choice type allows a value to be checked against a fixed set of + supported values. All of these values have to be strings. + + See :ref:`choice-opts` for an example. + """ + name = 'choice' + + def __init__(self, choices): + self.choices = choices + + def get_metavar(self, param): + return '[%s]' % '|'.join(self.choices) + + def get_missing_message(self, param): + return 'Choose from %s.' % ', '.join(self.choices) + + def convert(self, value, param, ctx): + # Exact match + if value in self.choices: + return value + + # Match through normalization + if ctx is not None and \ + ctx.token_normalize_func is not None: + value = ctx.token_normalize_func(value) + for choice in self.choices: + if ctx.token_normalize_func(choice) == value: + return choice + + self.fail('invalid choice: %s. (choose from %s)' % + (value, ', '.join(self.choices)), param, ctx) + + def __repr__(self): + return 'Choice(%r)' % list(self.choices) + + +class IntParamType(ParamType): + name = 'integer' + + def convert(self, value, param, ctx): + try: + return int(value) + except (ValueError, UnicodeError): + self.fail('%s is not a valid integer' % value, param, ctx) + + def __repr__(self): + return 'INT' + + +class IntRange(IntParamType): + """A parameter that works similar to :data:`click.INT` but restricts + the value to fit into a range. The default behavior is to fail if the + value falls outside the range, but it can also be silently clamped + between the two edges. + + See :ref:`ranges` for an example. + """ + name = 'integer range' + + def __init__(self, min=None, max=None, clamp=False): + self.min = min + self.max = max + self.clamp = clamp + + def convert(self, value, param, ctx): + rv = IntParamType.convert(self, value, param, ctx) + if self.clamp: + if self.min is not None and rv < self.min: + return self.min + if self.max is not None and rv > self.max: + return self.max + if self.min is not None and rv < self.min or \ + self.max is not None and rv > self.max: + if self.min is None: + self.fail('%s is bigger than the maximum valid value ' + '%s.' % (rv, self.max), param, ctx) + elif self.max is None: + self.fail('%s is smaller than the minimum valid value ' + '%s.' % (rv, self.min), param, ctx) + else: + self.fail('%s is not in the valid range of %s to %s.' + % (rv, self.min, self.max), param, ctx) + return rv + + def __repr__(self): + return 'IntRange(%r, %r)' % (self.min, self.max) + + +class BoolParamType(ParamType): + name = 'boolean' + + def convert(self, value, param, ctx): + if isinstance(value, bool): + return bool(value) + value = value.lower() + if value in ('true', '1', 'yes', 'y'): + return True + elif value in ('false', '0', 'no', 'n'): + return False + self.fail('%s is not a valid boolean' % value, param, ctx) + + def __repr__(self): + return 'BOOL' + + +class FloatParamType(ParamType): + name = 'float' + + def convert(self, value, param, ctx): + try: + return float(value) + except (UnicodeError, ValueError): + self.fail('%s is not a valid floating point value' % + value, param, ctx) + + def __repr__(self): + return 'FLOAT' + + +class UUIDParameterType(ParamType): + name = 'uuid' + + def convert(self, value, param, ctx): + import uuid + try: + if PY2 and isinstance(value, text_type): + value = value.encode('ascii') + return uuid.UUID(value) + except (UnicodeError, ValueError): + self.fail('%s is not a valid UUID value' % value, param, ctx) + + def __repr__(self): + return 'UUID' + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or + upon first IO. The default is to be non lazy for standard input and + output streams as well as files opened for reading, lazy otherwise. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + name = 'filename' + envvar_list_splitter = os.path.pathsep + + def __init__(self, mode='r', encoding=None, errors='strict', lazy=None, + atomic=False): + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def resolve_lazy_flag(self, value): + if self.lazy is not None: + return self.lazy + if value == '-': + return False + elif 'w' in self.mode: + return True + return False + + def convert(self, value, param, ctx): + try: + if hasattr(value, 'read') or hasattr(value, 'write'): + return value + + lazy = self.resolve_lazy_flag(value) + + if lazy: + f = LazyFile(value, self.mode, self.encoding, self.errors, + atomic=self.atomic) + if ctx is not None: + ctx.call_on_close(f.close_intelligently) + return f + + f, should_close = open_stream(value, self.mode, + self.encoding, self.errors, + atomic=self.atomic) + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + return f + except (IOError, OSError) as e: + self.fail('Could not open file: %s: %s' % ( + filename_to_ui(value), + get_streerror(e), + ), param, ctx) + + +class Path(ParamType): + """The path type is similar to the :class:`File` type but it performs + different checks. First of all, instead of returning an open file + handle it returns just the filename. Secondly, it can perform various + basic checks about what the file or directory should be. + + .. versionchanged:: 6.0 + `allow_dash` was added. + + :param exists: if set to true, the file or directory needs to exist for + this value to be valid. If this is not required and a + file does indeed not exist, then all further checks are + silently skipped. + :param file_okay: controls if a file is a possible value. + :param dir_okay: controls if a directory is a possible value. + :param writable: if true, a writable check is performed. + :param readable: if true, a readable check is performed. + :param resolve_path: if this is true, then the path is fully resolved + before the value is passed onwards. This means + that it's absolute and symlinks are resolved. + :param allow_dash: If this is set to `True`, a single dash to indicate + standard streams is permitted. + :param type: optionally a string type that should be used to + represent the path. The default is `None` which + means the return value will be either bytes or + unicode depending on what makes most sense given the + input data Click deals with. + """ + envvar_list_splitter = os.path.pathsep + + def __init__(self, exists=False, file_okay=True, dir_okay=True, + writable=False, readable=True, resolve_path=False, + allow_dash=False, path_type=None): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.writable = writable + self.readable = readable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name = 'file' + self.path_type = 'File' + if self.dir_okay and not self.file_okay: + self.name = 'directory' + self.path_type = 'Directory' + else: + self.name = 'path' + self.path_type = 'Path' + + def coerce_path_result(self, rv): + if self.type is not None and not isinstance(rv, self.type): + if self.type is text_type: + rv = rv.decode(get_filesystem_encoding()) + else: + rv = rv.encode(get_filesystem_encoding()) + return rv + + def convert(self, value, param, ctx): + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b'-', '-') + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail('%s "%s" does not exist.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail('%s "%s" is a file.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail('%s "%s" is a directory.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if self.writable and not os.access(value, os.W_OK): + self.fail('%s "%s" is not writable.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if self.readable and not os.access(value, os.R_OK): + self.fail('%s "%s" is not readable.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + + return self.coerce_path_result(rv) + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types): + self.types = [convert_type(ty) for ty in types] + + @property + def name(self): + return "<" + " ".join(ty.name for ty in self.types) + ">" + + @property + def arity(self): + return len(self.types) + + def convert(self, value, param, ctx): + if len(value) != len(self.types): + raise TypeError('It would appear that nargs is set to conflict ' + 'with the composite type arity.') + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty, default=None): + """Converts a callable or python ty into the most appropriate param + ty. + """ + guessed_type = False + if ty is None and default is not None: + if isinstance(default, tuple): + ty = tuple(map(type, default)) + else: + ty = type(default) + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + if isinstance(ty, ParamType): + return ty + if ty is text_type or ty is str or ty is None: + return STRING + if ty is int: + return INT + # Booleans are only okay if not guessed. This is done because for + # flags the default value is actually a bit of a lie in that it + # indicates which of the flags is the one we want. See get_default() + # for more information. + if ty is bool and not guessed_type: + return BOOL + if ty is float: + return FLOAT + if guessed_type: + return STRING + + # Catch a common mistake + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError('Attempted to use an uninstantiated ' + 'parameter type (%s).' % ty) + except TypeError: + pass + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but internally +#: no string conversion takes place. This is necessary to achieve the +#: same bytes/unicode behavior on Python 2/3 in situations where you want +#: to not convert argument types. This is usually useful when working +#: with file paths as they can appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/venv/lib/python2.7/site-packages/click/types.pyc b/venv/lib/python2.7/site-packages/click/types.pyc new file mode 100644 index 0000000..7463b3f Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/types.pyc differ diff --git a/venv/lib/python2.7/site-packages/click/utils.py b/venv/lib/python2.7/site-packages/click/utils.py new file mode 100644 index 0000000..eee626d --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/utils.py @@ -0,0 +1,415 @@ +import os +import sys + +from .globals import resolve_color_default + +from ._compat import text_type, open_stream, get_filesystem_encoding, \ + get_streerror, string_types, PY2, binary_streams, text_streams, \ + filename_to_ui, auto_wrap_for_ansi, strip_ansi, should_strip_ansi, \ + _default_text_stdout, _default_text_stderr, is_bytes, WIN + +if not PY2: + from ._compat import _find_binary_writer +elif WIN: + from ._winconsole import _get_windows_argv, \ + _hash_py_argv, _initial_argv_hash + + +echo_native_types = string_types + (bytes, bytearray) + + +def _posixify(name): + return '-'.join(name.split()).lower() + + +def safecall(func): + """Wraps a function so that it swallows exceptions.""" + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except Exception: + pass + return wrapper + + +def make_str(value): + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(get_filesystem_encoding()) + except UnicodeError: + return value.decode('utf-8', 'replace') + return text_type(value) + + +def make_default_short_help(help, max_length=45): + words = help.split() + total_length = 0 + result = [] + done = False + + for word in words: + if word[-1:] == '.': + done = True + new_length = result and 1 + len(word) or len(word) + if total_length + new_length > max_length: + result.append('...') + done = True + else: + if result: + result.append(' ') + result.append(word) + if done: + break + total_length += new_length + + return ''.join(result) + + +class LazyFile(object): + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__(self, filename, mode='r', encoding=None, errors='strict', + atomic=False): + self.name = filename + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + + if filename == '-': + self._f, self.should_close = open_stream(filename, mode, + encoding, errors) + else: + if 'r' in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name): + return getattr(self.open(), name) + + def __repr__(self): + if self._f is not None: + return repr(self._f) + return '' % (self.name, self.mode) + + def open(self): + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream(self.name, self.mode, + self.encoding, + self.errors, + atomic=self.atomic) + except (IOError, OSError) as e: + from .exceptions import FileError + raise FileError(self.name, hint=get_streerror(e)) + self._f = rv + return rv + + def close(self): + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self): + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.close_intelligently() + + def __iter__(self): + self.open() + return iter(self._f) + + +class KeepOpenFile(object): + + def __init__(self, file): + self._file = file + + def __getattr__(self, name): + return getattr(self._file, name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + pass + + def __repr__(self): + return repr(self._file) + + def __iter__(self): + return iter(self._file) + + +def echo(message=None, file=None, nl=True, err=False, color=None): + """Prints a message plus a newline to the given file or stdout. On + first sight, this looks like the print function, but it has improved + support for handling Unicode and binary data that does not fail no + matter how badly configured the system is. + + Primarily it means that you can print binary data as well as Unicode + data on both 2.x and 3.x to the given file in the most appropriate way + possible. This is a very carefree function as in that it will try its + best to not fail. As of Click 6.0 this includes support for unicode + output on the Windows console. + + In addition to that, if `colorama`_ is installed, the echo function will + also support clever handling of ANSI codes. Essentially it will then + do the following: + + - add transparent handling of ANSI color codes on Windows. + - hide ANSI codes automatically if the destination file is not a + terminal. + + .. _colorama: http://pypi.python.org/pypi/colorama + + .. versionchanged:: 6.0 + As of Click 6.0 the echo function will properly support unicode + output on the windows console. Not that click does not modify + the interpreter in any way which means that `sys.stdout` or the + print statement or function will still not provide unicode support. + + .. versionchanged:: 2.0 + Starting with version 2.0 of Click, the echo function will work + with colorama if it's installed. + + .. versionadded:: 3.0 + The `err` parameter was added. + + .. versionchanged:: 4.0 + Added the `color` flag. + + :param message: the message to print + :param file: the file to write to (defaults to ``stdout``) + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``. This is faster and easier than calling + :func:`get_text_stderr` yourself. + :param nl: if set to `True` (the default) a newline is printed afterwards. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, echo_native_types): + message = text_type(message) + + if nl: + message = message or u'' + if isinstance(message, text_type): + message += u'\n' + else: + message += b'\n' + + # If there is a message, and we're in Python 3, and the value looks + # like bytes, we manually need to find the binary stream and write the + # message in there. This is done separately so that most stream + # types will work as you would expect. Eg: you can write to StringIO + # for other cases. + if message and not PY2 and is_bytes(message): + binary_file = _find_binary_writer(file) + if binary_file is not None: + file.flush() + binary_file.write(message) + binary_file.flush() + return + + # ANSI-style support. If there is no message or we are dealing with + # bytes nothing is happening. If we are connected to a file we want + # to strip colors. If we are on windows we either wrap the stream + # to strip the color or we use the colorama support to translate the + # ansi codes to API calls. + if message and not is_bytes(message): + color = resolve_color_default(color) + if should_strip_ansi(file, color): + message = strip_ansi(message) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) + elif not color: + message = strip_ansi(message) + + if message: + file.write(message) + file.flush() + + +def get_binary_stream(name): + """Returns a system stream for byte processing. This essentially + returns the stream from the sys module with the given name but it + solves some compatibility issues between different Python versions. + Primarily this function is necessary for getting binary streams on + Python 3. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError('Unknown standard stream %r' % name) + return opener() + + +def get_text_stream(name, encoding=None, errors='strict'): + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts on Python 3 + for already correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError('Unknown standard stream %r' % name) + return opener(encoding, errors) + + +def open_file(filename, mode='r', encoding=None, errors='strict', + lazy=False, atomic=False): + """This is similar to how the :class:`File` works but for manual + usage. Files are opened non lazy by default. This can open regular + files as well as stdin/stdout if ``'-'`` is passed. + + If stdin/stdout is returned the stream is wrapped so that the context + manager will not close the stream accidentally. This makes it possible + to always use the function like this without having to worry to + accidentally close a standard stream:: + + with open_file(filename) as f: + ... + + .. versionadded:: 3.0 + + :param filename: the name of the file to open (or ``'-'`` for stdin/stdout). + :param mode: the mode in which to open the file. + :param encoding: the encoding to use. + :param errors: the error handling for this file. + :param lazy: can be flipped to true to open the file lazily. + :param atomic: in atomic mode writes go into a temporary file and it's + moved on close. + """ + if lazy: + return LazyFile(filename, mode, encoding, errors, atomic=atomic) + f, should_close = open_stream(filename, mode, encoding, errors, + atomic=atomic) + if not should_close: + f = KeepOpenFile(f) + return f + + +def get_os_args(): + """This returns the argument part of sys.argv in the most appropriate + form for processing. What this means is that this return value is in + a format that works for Click to process but does not necessarily + correspond well to what's actually standard for the interpreter. + + On most environments the return value is ``sys.argv[:1]`` unchanged. + However if you are on Windows and running Python 2 the return value + will actually be a list of unicode strings instead because the + default behavior on that platform otherwise will not be able to + carry all possible values that sys.argv can have. + + .. versionadded:: 6.0 + """ + # We can only extract the unicode argv if sys.argv has not been + # changed since the startup of the application. + if PY2 and WIN and _initial_argv_hash == _hash_py_argv(): + return _get_windows_argv() + return sys.argv[1:] + + +def format_filename(filename, shorten=False): + """Formats a filename for user display. The main purpose of this + function is to ensure that the filename can be displayed at all. This + will decode the filename to unicode if necessary in a way that it will + not fail. Optionally, it can shorten the filename to not include the + full path to the filename. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + return filename_to_ui(filename) + + +def get_app_dir(app_name, roaming=True, force_posix=False): + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Win XP (roaming): + ``C:\Documents and Settings\\Local Settings\Application Data\Foo Bar`` + Win XP (not roaming): + ``C:\Documents and Settings\\Application Data\Foo Bar`` + Win 7 (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Win 7 (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no affect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = roaming and 'APPDATA' or 'LOCALAPPDATA' + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser('~') + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser('~/.' + _posixify(app_name))) + if sys.platform == 'darwin': + return os.path.join(os.path.expanduser( + '~/Library/Application Support'), app_name) + return os.path.join( + os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), + _posixify(app_name)) diff --git a/venv/lib/python2.7/site-packages/click/utils.pyc b/venv/lib/python2.7/site-packages/click/utils.pyc new file mode 100644 index 0000000..fa1e865 Binary files /dev/null and b/venv/lib/python2.7/site-packages/click/utils.pyc differ diff --git a/venv/lib/python2.7/site-packages/easy_install.py b/venv/lib/python2.7/site-packages/easy_install.py new file mode 100644 index 0000000..d87e984 --- /dev/null +++ b/venv/lib/python2.7/site-packages/easy_install.py @@ -0,0 +1,5 @@ +"""Run the EasyInstall command""" + +if __name__ == '__main__': + from setuptools.command.easy_install import main + main() diff --git a/venv/lib/python2.7/site-packages/easy_install.pyc b/venv/lib/python2.7/site-packages/easy_install.pyc new file mode 100644 index 0000000..324c85b Binary files /dev/null and b/venv/lib/python2.7/site-packages/easy_install.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/__init__.py b/venv/lib/python2.7/site-packages/flask/__init__.py new file mode 100644 index 0000000..2fcb356 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/__init__.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +""" + flask + ~~~~~ + + A microframework based on Werkzeug. It's extensively documented + and follows best practice patterns. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +__version__ = '0.12.1' + +# utilities we import from Werkzeug and Jinja2 that are unused +# in the module but are exported as public interface. +from werkzeug.exceptions import abort +from werkzeug.utils import redirect +from jinja2 import Markup, escape + +from .app import Flask, Request, Response +from .config import Config +from .helpers import url_for, flash, send_file, send_from_directory, \ + get_flashed_messages, get_template_attribute, make_response, safe_join, \ + stream_with_context +from .globals import current_app, g, request, session, _request_ctx_stack, \ + _app_ctx_stack +from .ctx import has_request_context, has_app_context, \ + after_this_request, copy_current_request_context +from .blueprints import Blueprint +from .templating import render_template, render_template_string + +# the signals +from .signals import signals_available, template_rendered, request_started, \ + request_finished, got_request_exception, request_tearing_down, \ + appcontext_tearing_down, appcontext_pushed, \ + appcontext_popped, message_flashed, before_render_template + +# We're not exposing the actual json module but a convenient wrapper around +# it. +from . import json + +# This was the only thing that Flask used to export at one point and it had +# a more generic name. +jsonify = json.jsonify + +# backwards compat, goes away in 1.0 +from .sessions import SecureCookieSession as Session +json_available = True diff --git a/venv/lib/python2.7/site-packages/flask/__init__.pyc b/venv/lib/python2.7/site-packages/flask/__init__.pyc new file mode 100644 index 0000000..1ad9407 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/__init__.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/__main__.py b/venv/lib/python2.7/site-packages/flask/__main__.py new file mode 100644 index 0000000..cbefccd --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/__main__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +""" + flask.__main__ + ~~~~~~~~~~~~~~ + + Alias for flask.run for the command line. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + + +if __name__ == '__main__': + from .cli import main + main(as_module=True) diff --git a/venv/lib/python2.7/site-packages/flask/__main__.pyc b/venv/lib/python2.7/site-packages/flask/__main__.pyc new file mode 100644 index 0000000..b41c5b1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/__main__.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/_compat.py b/venv/lib/python2.7/site-packages/flask/_compat.py new file mode 100644 index 0000000..071628f --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/_compat.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +""" + flask._compat + ~~~~~~~~~~~~~ + + Some py2/py3 compatibility support based on a stripped down + version of six so we don't have to depend on a specific version + of it. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import sys + +PY2 = sys.version_info[0] == 2 +_identity = lambda x: x + + +if not PY2: + text_type = str + string_types = (str,) + integer_types = (int,) + + iterkeys = lambda d: iter(d.keys()) + itervalues = lambda d: iter(d.values()) + iteritems = lambda d: iter(d.items()) + + from io import StringIO + + def reraise(tp, value, tb=None): + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + + implements_to_string = _identity + +else: + text_type = unicode + string_types = (str, unicode) + integer_types = (int, long) + + iterkeys = lambda d: d.iterkeys() + itervalues = lambda d: d.itervalues() + iteritems = lambda d: d.iteritems() + + from cStringIO import StringIO + + exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') + + def implements_to_string(cls): + cls.__unicode__ = cls.__str__ + cls.__str__ = lambda x: x.__unicode__().encode('utf-8') + return cls + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a + # dummy metaclass for one level of class instantiation that replaces + # itself with the actual metaclass. + class metaclass(type): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +# Certain versions of pypy have a bug where clearing the exception stack +# breaks the __exit__ function in a very peculiar way. The second level of +# exception blocks is necessary because pypy seems to forget to check if an +# exception happened until the next bytecode instruction? +# +# Relevant PyPy bugfix commit: +# https://bitbucket.org/pypy/pypy/commits/77ecf91c635a287e88e60d8ddb0f4e9df4003301 +# According to ronan on #pypy IRC, it is released in PyPy2 2.3 and later +# versions. +# +# Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug. +BROKEN_PYPY_CTXMGR_EXIT = False +if hasattr(sys, 'pypy_version_info'): + class _Mgr(object): + def __enter__(self): + return self + def __exit__(self, *args): + if hasattr(sys, 'exc_clear'): + # Python 3 (PyPy3) doesn't have exc_clear + sys.exc_clear() + try: + try: + with _Mgr(): + raise AssertionError() + except: + raise + except TypeError: + BROKEN_PYPY_CTXMGR_EXIT = True + except AssertionError: + pass diff --git a/venv/lib/python2.7/site-packages/flask/_compat.pyc b/venv/lib/python2.7/site-packages/flask/_compat.pyc new file mode 100644 index 0000000..42ec57a Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/_compat.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/app.py b/venv/lib/python2.7/site-packages/flask/app.py new file mode 100644 index 0000000..1404e17 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/app.py @@ -0,0 +1,2003 @@ +# -*- coding: utf-8 -*- +""" + flask.app + ~~~~~~~~~ + + This module implements the central WSGI application object. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import os +import sys +from threading import Lock +from datetime import timedelta +from itertools import chain +from functools import update_wrapper + +from werkzeug.datastructures import ImmutableDict +from werkzeug.routing import Map, Rule, RequestRedirect, BuildError +from werkzeug.exceptions import HTTPException, InternalServerError, \ + MethodNotAllowed, BadRequest, default_exceptions + +from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \ + locked_cached_property, _endpoint_from_view_func, find_package, \ + get_debug_flag +from . import json, cli +from .wrappers import Request, Response +from .config import ConfigAttribute, Config +from .ctx import RequestContext, AppContext, _AppCtxGlobals +from .globals import _request_ctx_stack, request, session, g +from .sessions import SecureCookieSessionInterface +from .templating import DispatchingJinjaLoader, Environment, \ + _default_template_ctx_processor +from .signals import request_started, request_finished, got_request_exception, \ + request_tearing_down, appcontext_tearing_down +from ._compat import reraise, string_types, text_type, integer_types + +# a lock used for logger initialization +_logger_lock = Lock() + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +def _make_timedelta(value): + if not isinstance(value, timedelta): + return timedelta(seconds=value) + return value + + +def setupmethod(f): + """Wraps a method so that it performs a check in debug mode if the + first request was already handled. + """ + def wrapper_func(self, *args, **kwargs): + if self.debug and self._got_first_request: + raise AssertionError('A setup function was called after the ' + 'first request was handled. This usually indicates a bug ' + 'in the application where a module was not imported ' + 'and decorators or other functionality was called too late.\n' + 'To fix this make sure to import all your view modules, ' + 'database models and everything related at a central place ' + 'before the application starts serving requests.') + return f(self, *args, **kwargs) + return update_wrapper(wrapper_func, f) + + +class Flask(_PackageBoundObject): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: the folder with static files that should be served + at `static_url_path`. Defaults to the ``'static'`` + folder in the root path of the application. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: Flask by default will automatically calculate the path + to the root of the application. In certain situations + this cannot be achieved (for instance if the package + is a Python 3 namespace package) and needs to be + manually defined. + """ + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class = Response + + #: The class that is used for the Jinja environment. + #: + #: .. versionadded:: 0.11 + jinja_environment = Environment + + #: The class that is used for the :data:`~flask.g` instance. + #: + #: Example use cases for a custom class: + #: + #: 1. Store arbitrary attributes on flask.g. + #: 2. Add a property for lazy per-request database connectors. + #: 3. Return None instead of AttributeError on unexpected attributes. + #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. + #: + #: In Flask 0.9 this property was called `request_globals_class` but it + #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the + #: flask.g object is now application context scoped. + #: + #: .. versionadded:: 0.10 + app_ctx_globals_class = _AppCtxGlobals + + # Backwards compatibility support + def _get_request_globals_class(self): + return self.app_ctx_globals_class + def _set_request_globals_class(self, value): + from warnings import warn + warn(DeprecationWarning('request_globals_class attribute is now ' + 'called app_ctx_globals_class')) + self.app_ctx_globals_class = value + request_globals_class = property(_get_request_globals_class, + _set_request_globals_class) + del _get_request_globals_class, _set_request_globals_class + + #: The class that is used for the ``config`` attribute of this app. + #: Defaults to :class:`~flask.Config`. + #: + #: Example use cases for a custom class: + #: + #: 1. Default values for certain config options. + #: 2. Access to config values through attributes in addition to keys. + #: + #: .. versionadded:: 0.11 + config_class = Config + + #: The debug flag. Set this to ``True`` to enable debugging of the + #: application. In debug mode the debugger will kick in when an unhandled + #: exception occurs and the integrated server will automatically reload + #: the application if changes in the code are detected. + #: + #: This attribute can also be configured from the config with the ``DEBUG`` + #: configuration key. Defaults to ``False``. + debug = ConfigAttribute('DEBUG') + + #: The testing flag. Set this to ``True`` to enable the test mode of + #: Flask extensions (and in the future probably also Flask itself). + #: For example this might activate unittest helpers that have an + #: additional runtime cost which should not be enabled by default. + #: + #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the + #: default it's implicitly enabled. + #: + #: This attribute can also be configured from the config with the + #: ``TESTING`` configuration key. Defaults to ``False``. + testing = ConfigAttribute('TESTING') + + #: If a secret key is set, cryptographic components can use this to + #: sign cookies and other things. Set this to a complex random value + #: when you want to use the secure cookie for instance. + #: + #: This attribute can also be configured from the config with the + #: ``SECRET_KEY`` configuration key. Defaults to ``None``. + secret_key = ConfigAttribute('SECRET_KEY') + + #: The secure cookie uses this for the name of the session cookie. + #: + #: This attribute can also be configured from the config with the + #: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'`` + session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME') + + #: A :class:`~datetime.timedelta` which is used to set the expiration + #: date of a permanent session. The default is 31 days which makes a + #: permanent session survive for roughly one month. + #: + #: This attribute can also be configured from the config with the + #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to + #: ``timedelta(days=31)`` + permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME', + get_converter=_make_timedelta) + + #: A :class:`~datetime.timedelta` which is used as default cache_timeout + #: for the :func:`send_file` functions. The default is 12 hours. + #: + #: This attribute can also be configured from the config with the + #: ``SEND_FILE_MAX_AGE_DEFAULT`` configuration key. This configuration + #: variable can also be set with an integer value used as seconds. + #: Defaults to ``timedelta(hours=12)`` + send_file_max_age_default = ConfigAttribute('SEND_FILE_MAX_AGE_DEFAULT', + get_converter=_make_timedelta) + + #: Enable this if you want to use the X-Sendfile feature. Keep in + #: mind that the server has to support this. This only affects files + #: sent with the :func:`send_file` method. + #: + #: .. versionadded:: 0.2 + #: + #: This attribute can also be configured from the config with the + #: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``. + use_x_sendfile = ConfigAttribute('USE_X_SENDFILE') + + #: The name of the logger to use. By default the logger name is the + #: package name passed to the constructor. + #: + #: .. versionadded:: 0.4 + logger_name = ConfigAttribute('LOGGER_NAME') + + #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`. + #: + #: .. versionadded:: 0.10 + json_encoder = json.JSONEncoder + + #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`. + #: + #: .. versionadded:: 0.10 + json_decoder = json.JSONDecoder + + #: Options that are passed directly to the Jinja2 environment. + jinja_options = ImmutableDict( + extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] + ) + + #: Default configuration parameters. + default_config = ImmutableDict({ + 'DEBUG': get_debug_flag(default=False), + 'TESTING': False, + 'PROPAGATE_EXCEPTIONS': None, + 'PRESERVE_CONTEXT_ON_EXCEPTION': None, + 'SECRET_KEY': None, + 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), + 'USE_X_SENDFILE': False, + 'LOGGER_NAME': None, + 'LOGGER_HANDLER_POLICY': 'always', + 'SERVER_NAME': None, + 'APPLICATION_ROOT': None, + 'SESSION_COOKIE_NAME': 'session', + 'SESSION_COOKIE_DOMAIN': None, + 'SESSION_COOKIE_PATH': None, + 'SESSION_COOKIE_HTTPONLY': True, + 'SESSION_COOKIE_SECURE': False, + 'SESSION_REFRESH_EACH_REQUEST': True, + 'MAX_CONTENT_LENGTH': None, + 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), + 'TRAP_BAD_REQUEST_ERRORS': False, + 'TRAP_HTTP_EXCEPTIONS': False, + 'EXPLAIN_TEMPLATE_LOADING': False, + 'PREFERRED_URL_SCHEME': 'http', + 'JSON_AS_ASCII': True, + 'JSON_SORT_KEYS': True, + 'JSONIFY_PRETTYPRINT_REGULAR': True, + 'JSONIFY_MIMETYPE': 'application/json', + 'TEMPLATES_AUTO_RELOAD': None, + }) + + #: The rule object to use for URL rules created. This is used by + #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. + #: + #: .. versionadded:: 0.7 + url_rule_class = Rule + + #: the test client that is used with when `test_client` is used. + #: + #: .. versionadded:: 0.7 + test_client_class = None + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface = SecureCookieSessionInterface() + + def __init__(self, import_name, static_path=None, static_url_path=None, + static_folder='static', template_folder='templates', + instance_path=None, instance_relative_config=False, + root_path=None): + _PackageBoundObject.__init__(self, import_name, + template_folder=template_folder, + root_path=root_path) + if static_path is not None: + from warnings import warn + warn(DeprecationWarning('static_path is now called ' + 'static_url_path'), stacklevel=2) + static_url_path = static_path + + if static_url_path is not None: + self.static_url_path = static_url_path + if static_folder is not None: + self.static_folder = static_folder + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError('If an instance path is provided it must be ' + 'absolute. A relative path was given instead.') + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + # Prepare the deferred setup of the logger. + self._logger = None + self.logger_name = self.import_name + + #: A dictionary of all view functions registered. The keys will + #: be function names which are also used to generate URLs and + #: the values are the function objects themselves. + #: To register a view function, use the :meth:`route` decorator. + self.view_functions = {} + + # support for the now deprecated `error_handlers` attribute. The + # :attr:`error_handler_spec` shall be used now. + self._error_handlers = {} + + #: A dictionary of all registered error handlers. The key is ``None`` + #: for error handlers active on the application, otherwise the key is + #: the name of the blueprint. Each key points to another dictionary + #: where the key is the status code of the http exception. The + #: special key ``None`` points to a list of tuples where the first item + #: is the class for the instance check and the second the error handler + #: function. + #: + #: To register a error handler, use the :meth:`errorhandler` + #: decorator. + self.error_handler_spec = {None: self._error_handlers} + + #: A list of functions that are called when :meth:`url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function registered here + #: is called with `error`, `endpoint` and `values`. If a function + #: returns ``None`` or raises a :exc:`BuildError` the next function is + #: tried. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers = [] + + #: A dictionary with lists of functions that should be called at the + #: beginning of the request. The key of the dictionary is the name of + #: the blueprint this function is active for, ``None`` for all requests. + #: This can for example be used to open database connections or + #: getting hold of the currently logged in user. To register a + #: function here, use the :meth:`before_request` decorator. + self.before_request_funcs = {} + + #: A lists of functions that should be called at the beginning of the + #: first request to this instance. To register a function here, use + #: the :meth:`before_first_request` decorator. + #: + #: .. versionadded:: 0.8 + self.before_first_request_funcs = [] + + #: A dictionary with lists of functions that should be called after + #: each request. The key of the dictionary is the name of the blueprint + #: this function is active for, ``None`` for all requests. This can for + #: example be used to close database connections. To register a function + #: here, use the :meth:`after_request` decorator. + self.after_request_funcs = {} + + #: A dictionary with lists of functions that are called after + #: each request, even if an exception has occurred. The key of the + #: dictionary is the name of the blueprint this function is active for, + #: ``None`` for all requests. These functions are not allowed to modify + #: the request, and their return values are ignored. If an exception + #: occurred while processing the request, it gets passed to each + #: teardown_request function. To register a function here, use the + #: :meth:`teardown_request` decorator. + #: + #: .. versionadded:: 0.7 + self.teardown_request_funcs = {} + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs = [] + + #: A dictionary with lists of functions that can be used as URL + #: value processor functions. Whenever a URL is built these functions + #: are called to modify the dictionary of values in place. The key + #: ``None`` here is used for application wide + #: callbacks, otherwise the key is the name of the blueprint. + #: Each of these functions has the chance to modify the dictionary + #: + #: .. versionadded:: 0.7 + self.url_value_preprocessors = {} + + #: A dictionary with lists of functions that can be used as URL value + #: preprocessors. The key ``None`` here is used for application wide + #: callbacks, otherwise the key is the name of the blueprint. + #: Each of these functions has the chance to modify the dictionary + #: of URL values before they are used as the keyword arguments of the + #: view function. For each function registered this one should also + #: provide a :meth:`url_defaults` function that adds the parameters + #: automatically again that were removed that way. + #: + #: .. versionadded:: 0.7 + self.url_default_functions = {} + + #: A dictionary with list of functions that are called without argument + #: to populate the template context. The key of the dictionary is the + #: name of the blueprint this function is active for, ``None`` for all + #: requests. Each returns a dictionary that the template context is + #: updated with. To register a function here, use the + #: :meth:`context_processor` decorator. + self.template_context_processors = { + None: [_default_template_ctx_processor] + } + + #: A list of shell context processor functions that should be run + #: when a shell context is created. + #: + #: .. versionadded:: 0.11 + self.shell_context_processors = [] + + #: all the attached blueprints in a dictionary by name. Blueprints + #: can be attached multiple times so this dictionary does not tell + #: you how often they got attached. + #: + #: .. versionadded:: 0.7 + self.blueprints = {} + self._blueprint_order = [] + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. For backwards compatibility extensions should register + #: themselves like this:: + #: + #: if not hasattr(app, 'extensions'): + #: app.extensions = {} + #: app.extensions['extensionname'] = SomeObject() + #: + #: The key must match the name of the extension module. For example in + #: case of a "Flask-Foo" extension in `flask_foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions = {} + + #: The :class:`~werkzeug.routing.Map` for this instance. You can use + #: this to change the routing converters after the class was created + #: but before any routes are connected. Example:: + #: + #: from werkzeug.routing import BaseConverter + #: + #: class ListConverter(BaseConverter): + #: def to_python(self, value): + #: return value.split(',') + #: def to_url(self, values): + #: return ','.join(super(ListConverter, self).to_url(value) + #: for value in values) + #: + #: app = Flask(__name__) + #: app.url_map.converters['list'] = ListConverter + self.url_map = Map() + + # tracks internally if the application already handled at least one + # request. + self._got_first_request = False + self._before_request_lock = Lock() + + # register the static folder for the application. Do that even + # if the folder does not exist. First of all it might be created + # while the server is running (usually happens during development) + # but also because google appengine stores static files somewhere + # else when mapped with the .yml file. + if self.has_static_folder: + self.add_url_rule(self.static_url_path + '/', + endpoint='static', + view_func=self.send_static_file) + + #: The click command line context for this application. Commands + #: registered here show up in the :command:`flask` command once the + #: application has been discovered. The default commands are + #: provided by Flask itself and can be overridden. + #: + #: This is an instance of a :class:`click.Group` object. + self.cli = cli.AppGroup(self.name) + + def _get_error_handlers(self): + from warnings import warn + warn(DeprecationWarning('error_handlers is deprecated, use the ' + 'new error_handler_spec attribute instead.'), stacklevel=1) + return self._error_handlers + def _set_error_handlers(self, value): + self._error_handlers = value + self.error_handler_spec[None] = value + error_handlers = property(_get_error_handlers, _set_error_handlers) + del _get_error_handlers, _set_error_handlers + + @locked_cached_property + def name(self): + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overridden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == '__main__': + fn = getattr(sys.modules['__main__'], '__file__', None) + if fn is None: + return '__main__' + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + + @property + def propagate_exceptions(self): + """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration + value in case it's set, otherwise a sensible default is returned. + + .. versionadded:: 0.7 + """ + rv = self.config['PROPAGATE_EXCEPTIONS'] + if rv is not None: + return rv + return self.testing or self.debug + + @property + def preserve_context_on_exception(self): + """Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION`` + configuration value in case it's set, otherwise a sensible default + is returned. + + .. versionadded:: 0.7 + """ + rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION'] + if rv is not None: + return rv + return self.debug + + @property + def logger(self): + """A :class:`logging.Logger` object for this application. The + default configuration is to log to stderr if the application is + in debug mode. This logger can be used to (surprise) log messages. + Here some examples:: + + app.logger.debug('A value for debugging') + app.logger.warning('A warning occurred (%d apples)', 42) + app.logger.error('An error occurred') + + .. versionadded:: 0.3 + """ + if self._logger and self._logger.name == self.logger_name: + return self._logger + with _logger_lock: + if self._logger and self._logger.name == self.logger_name: + return self._logger + from flask.logging import create_logger + self._logger = rv = create_logger(self) + return rv + + @locked_cached_property + def jinja_env(self): + """The Jinja2 environment used to load templates.""" + return self.create_jinja_environment() + + @property + def got_first_request(self): + """This attribute is set to ``True`` if the application started + handling the first request. + + .. versionadded:: 0.8 + """ + return self._got_first_request + + def make_config(self, instance_relative=False): + """Used to create the config attribute by the Flask constructor. + The `instance_relative` parameter is passed in from the constructor + of Flask (there named `instance_relative_config`) and indicates if + the config should be relative to the instance path or the root path + of the application. + + .. versionadded:: 0.8 + """ + root_path = self.root_path + if instance_relative: + root_path = self.instance_path + return self.config_class(root_path, self.default_config) + + def auto_find_instance_path(self): + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, 'instance') + return os.path.join(prefix, 'var', self.name + '-instance') + + def open_instance_resource(self, resource, mode='rb'): + """Opens a resource from the application's instance folder + (:attr:`instance_path`). Otherwise works like + :meth:`open_resource`. Instance resources can also be opened for + writing. + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + return open(os.path.join(self.instance_path, resource), mode) + + def create_jinja_environment(self): + """Creates the Jinja2 environment based on :attr:`jinja_options` + and :meth:`select_jinja_autoescape`. Since 0.7 this also adds + the Jinja2 globals and filters after initialization. Override + this function to customize the behavior. + + .. versionadded:: 0.5 + .. versionchanged:: 0.11 + ``Environment.auto_reload`` set in accordance with + ``TEMPLATES_AUTO_RELOAD`` configuration option. + """ + options = dict(self.jinja_options) + if 'autoescape' not in options: + options['autoescape'] = self.select_jinja_autoescape + if 'auto_reload' not in options: + if self.config['TEMPLATES_AUTO_RELOAD'] is not None: + options['auto_reload'] = self.config['TEMPLATES_AUTO_RELOAD'] + else: + options['auto_reload'] = self.debug + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g + ) + rv.filters['tojson'] = json.tojson_filter + return rv + + def create_global_jinja_loader(self): + """Creates the loader for the Jinja2 environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def init_jinja_globals(self): + """Deprecated. Used to initialize the Jinja2 globals. + + .. versionadded:: 0.5 + .. versionchanged:: 0.7 + This method is deprecated with 0.7. Override + :meth:`create_jinja_environment` instead. + """ + + def select_jinja_autoescape(self, filename): + """Returns ``True`` if autoescaping should be active for the given + template name. If no template name is given, returns `True`. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith(('.html', '.htm', '.xml', '.xhtml')) + + def update_template_context(self, context): + """Update the template context with some commonly used variables. + This injects request, session, config and g into the template + context as well as everything template context processors want + to inject. Note that the as of Flask 0.6, the original values + in the context will not be overridden if a context processor + decides to return a value with the same key. + + :param context: the context as a dictionary that is updated in place + to add extra variables. + """ + funcs = self.template_context_processors[None] + reqctx = _request_ctx_stack.top + if reqctx is not None: + bp = reqctx.request.blueprint + if bp is not None and bp in self.template_context_processors: + funcs = chain(funcs, self.template_context_processors[bp]) + orig_ctx = context.copy() + for func in funcs: + context.update(func()) + # make sure the original values win. This makes it possible to + # easier add new variables in context processors without breaking + # existing views. + context.update(orig_ctx) + + def make_shell_context(self): + """Returns the shell context for an interactive shell for this + application. This runs all the registered shell context + processors. + + .. versionadded:: 0.11 + """ + rv = {'app': self, 'g': g} + for processor in self.shell_context_processors: + rv.update(processor()) + return rv + + def run(self, host=None, port=None, debug=None, **options): + """Runs the application on a local development server. + + Do not use ``run()`` in a production setting. It is not intended to + meet security and performance requirements for a production server. + Instead, see :ref:`deployment` for WSGI server recommendations. + + If the :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + It is not recommended to use this function for development with + automatic reloading as this is badly supported. Instead you should + be using the :command:`flask` command line script's ``run`` support. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to ``True`` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` variable. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'``. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if + present. + :param debug: if given, enable or disable debug mode. + See :attr:`debug`. + :param options: the options to be forwarded to the underlying + Werkzeug server. See + :func:`werkzeug.serving.run_simple` for more + information. + """ + from werkzeug.serving import run_simple + if host is None: + host = '127.0.0.1' + if port is None: + server_name = self.config['SERVER_NAME'] + if server_name and ':' in server_name: + port = int(server_name.rsplit(':', 1)[1]) + else: + port = 5000 + if debug is not None: + self.debug = bool(debug) + options.setdefault('use_reloader', self.debug) + options.setdefault('use_debugger', self.debug) + try: + run_simple(host, port, self, **options) + finally: + # reset the first request information if the development server + # reset normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies=True, **kwargs): + """Creates a test client for this application. For information + about unit testing head over to :ref:`testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a ``with`` block to defer the closing down + of the context until the end of the ``with`` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + Additionally, you may pass optional keyword arguments that will then + be passed to the application's :attr:`test_client_class` constructor. + For example:: + + from flask.testing import FlaskClient + + class CustomClient(FlaskClient): + def __init__(self, *args, **kwargs): + self._authentication = kwargs.pop("authentication") + super(CustomClient,self).__init__( *args, **kwargs) + + app.test_client_class = CustomClient + client = app.test_client(authentication='Basic ....') + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for ``with`` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + + .. versionchanged:: 0.11 + Added `**kwargs` to support passing additional keyword arguments to + the constructor of :attr:`test_client_class`. + """ + cls = self.test_client_class + if cls is None: + from flask.testing import FlaskClient as cls + return cls(self, self.response_class, use_cookies=use_cookies, **kwargs) + + def open_session(self, request): + """Creates or opens a new session. Default implementation stores all + session data in a signed cookie. This requires that the + :attr:`secret_key` is set. Instead of overriding this method + we recommend replacing the :class:`session_interface`. + + :param request: an instance of :attr:`request_class`. + """ + return self.session_interface.open_session(self, request) + + def save_session(self, session, response): + """Saves the session if it needs updates. For the default + implementation, check :meth:`open_session`. Instead of overriding this + method we recommend replacing the :class:`session_interface`. + + :param session: the session to be saved (a + :class:`~werkzeug.contrib.securecookie.SecureCookie` + object) + :param response: an instance of :attr:`response_class` + """ + return self.session_interface.save_session(self, session, response) + + def make_null_session(self): + """Creates a new instance of a missing session. Instead of overriding + this method we recommend replacing the :class:`session_interface`. + + .. versionadded:: 0.7 + """ + return self.session_interface.make_null_session(self) + + @setupmethod + def register_blueprint(self, blueprint, **options): + """Registers a blueprint on the application. + + .. versionadded:: 0.7 + """ + first_registration = False + if blueprint.name in self.blueprints: + assert self.blueprints[blueprint.name] is blueprint, \ + 'A blueprint\'s name collision occurred between %r and ' \ + '%r. Both share the same name "%s". Blueprints that ' \ + 'are created on the fly need unique names.' % \ + (blueprint, self.blueprints[blueprint.name], blueprint.name) + else: + self.blueprints[blueprint.name] = blueprint + self._blueprint_order.append(blueprint) + first_registration = True + blueprint.register(self, options, first_registration) + + def iter_blueprints(self): + """Iterates over all blueprints by the order they were registered. + + .. versionadded:: 0.11 + """ + return iter(self._blueprint_order) + + @setupmethod + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """Connects a URL rule. Works exactly like the :meth:`route` + decorator. If a view_func is provided it will be registered with the + endpoint. + + Basically this example:: + + @app.route('/') + def index(): + pass + + Is equivalent to the following:: + + def index(): + pass + app.add_url_rule('/', 'index', index) + + If the view_func is not provided you will need to connect the endpoint + to a view function like so:: + + app.view_functions['index'] = index + + Internally :meth:`route` invokes :meth:`add_url_rule` so if you want + to customize the behavior via subclassing you only need to change + this method. + + For more information refer to :ref:`url-route-registrations`. + + .. versionchanged:: 0.2 + `view_func` parameter added. + + .. versionchanged:: 0.6 + ``OPTIONS`` is added automatically as method. + + :param rule: the URL rule as string + :param endpoint: the endpoint for the registered URL rule. Flask + itself assumes the name of the view function as + endpoint + :param view_func: the function to call when serving a request to the + provided endpoint + :param options: the options to be forwarded to the underlying + :class:`~werkzeug.routing.Rule` object. A change + to Werkzeug is handling of method options. methods + is a list of methods this rule should be limited + to (``GET``, ``POST`` etc.). By default a rule + just listens for ``GET`` (and implicitly ``HEAD``). + Starting with Flask 0.6, ``OPTIONS`` is implicitly + added and handled by the standard request handling. + """ + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) + options['endpoint'] = endpoint + methods = options.pop('methods', None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, 'methods', None) or ('GET',) + if isinstance(methods, string_types): + raise TypeError('Allowed methods have to be iterables of strings, ' + 'for example: @app.route(..., methods=["POST"])') + methods = set(item.upper() for item in methods) + + # Methods that should always be added + required_methods = set(getattr(view_func, 'required_methods', ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + provide_automatic_options = getattr(view_func, + 'provide_automatic_options', None) + + if provide_automatic_options is None: + if 'OPTIONS' not in methods: + provide_automatic_options = True + required_methods.add('OPTIONS') + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule = self.url_rule_class(rule, methods=methods, **options) + rule.provide_automatic_options = provide_automatic_options + + self.url_map.add(rule) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError('View function mapping is overwriting an ' + 'existing endpoint function: %s' % endpoint) + self.view_functions[endpoint] = view_func + + def route(self, rule, **options): + """A decorator that is used to register a view function for a + given URL rule. This does the same thing as :meth:`add_url_rule` + but is intended for decorator usage:: + + @app.route('/') + def index(): + return 'Hello World' + + For more information refer to :ref:`url-route-registrations`. + + :param rule: the URL rule as string + :param endpoint: the endpoint for the registered URL rule. Flask + itself assumes the name of the view function as + endpoint + :param options: the options to be forwarded to the underlying + :class:`~werkzeug.routing.Rule` object. A change + to Werkzeug is handling of method options. methods + is a list of methods this rule should be limited + to (``GET``, ``POST`` etc.). By default a rule + just listens for ``GET`` (and implicitly ``HEAD``). + Starting with Flask 0.6, ``OPTIONS`` is implicitly + added and handled by the standard request handling. + """ + def decorator(f): + endpoint = options.pop('endpoint', None) + self.add_url_rule(rule, endpoint, f, **options) + return f + return decorator + + @setupmethod + def endpoint(self, endpoint): + """A decorator to register a function as an endpoint. + Example:: + + @app.endpoint('example.endpoint') + def example(): + return "example" + + :param endpoint: the name of the endpoint + """ + def decorator(f): + self.view_functions[endpoint] = f + return f + return decorator + + @staticmethod + def _get_exc_class_and_code(exc_class_or_code): + """Ensure that we register only exceptions as handler keys""" + if isinstance(exc_class_or_code, integer_types): + exc_class = default_exceptions[exc_class_or_code] + else: + exc_class = exc_class_or_code + + assert issubclass(exc_class, Exception) + + if issubclass(exc_class, HTTPException): + return exc_class, exc_class.code + else: + return exc_class, None + + @setupmethod + def errorhandler(self, code_or_exception): + """A decorator that is used to register a function given an + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + You can also register a function as error handler without using + the :meth:`errorhandler` decorator. The following example is + equivalent to the one above:: + + def page_not_found(error): + return 'This page does not exist', 404 + app.error_handler_spec[None][404] = page_not_found + + Setting error handlers via assignments to :attr:`error_handler_spec` + however is discouraged as it requires fiddling with nested dictionaries + and the special case for arbitrary exception types. + + The first ``None`` refers to the active blueprint. If the error + handler should be application wide ``None`` shall be used. + + .. versionadded:: 0.7 + Use :meth:`register_error_handler` instead of modifying + :attr:`error_handler_spec` directly, for application wide error + handlers. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code_or_exception: the code as integer for the handler, or + an arbitrary exception + """ + def decorator(f): + self._register_error_handler(None, code_or_exception, f) + return f + return decorator + + def register_error_handler(self, code_or_exception, f): + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + self._register_error_handler(None, code_or_exception, f) + + @setupmethod + def _register_error_handler(self, key, code_or_exception, f): + """ + :type key: None|str + :type code_or_exception: int|T<=Exception + :type f: callable + """ + if isinstance(code_or_exception, HTTPException): # old broken behavior + raise ValueError( + 'Tried to register a handler for an exception instance {0!r}. ' + 'Handlers can only be registered for exception classes or HTTP error codes.' + .format(code_or_exception)) + + exc_class, code = self._get_exc_class_and_code(code_or_exception) + + handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {}) + handlers[exc_class] = f + + @setupmethod + def template_filter(self, name=None): + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_filter(f, name=name) + return f + return decorator + + @setupmethod + def add_template_filter(self, f, name=None): + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test(self, name=None): + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_test(f, name=name) + return f + return decorator + + @setupmethod + def add_template_test(self, f, name=None): + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global(self, name=None): + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_global(f, name=name) + return f + return decorator + + @setupmethod + def add_template_global(self, f, name=None): + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def before_request(self, f): + """Registers a function to run before each request. + + The function will be called without any arguments. + If the function returns a non-None value, it's handled as + if it was the return value from the view and further + request handling is stopped. + """ + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def before_first_request(self, f): + """Registers a function to be run before the first request to this + instance of the application. + + The function will be called without any arguments and its return + value is ignored. + + .. versionadded:: 0.8 + """ + self.before_first_request_funcs.append(f) + return f + + @setupmethod + def after_request(self, f): + """Register a function to be run after each request. + + Your function must take one parameter, an instance of + :attr:`response_class` and return a new response object or the + same (see :meth:`process_response`). + + As of Flask 0.7 this function might not be executed at the end of the + request in case an unhandled exception occurred. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f): + """Register a function to be run at the end of each request, + regardless of whether there was an exception or not. These functions + are executed when the request context is popped, even if not an + actual request was performed. + + Example:: + + ctx = app.test_request_context() + ctx.push() + ... + ctx.pop() + + When ``ctx.pop()`` is executed in the above example, the teardown + functions are called just before the request context moves from the + stack of active contexts. This becomes relevant if you are using + such constructs in tests. + + Generally teardown functions must take every necessary step to avoid + that they will fail. If they do execute code that might fail they + will have to surround the execution of these code by try/except + statements and log occurring errors. + + When a teardown function was called because of a exception it will + be passed an error object. + + The return values of teardown functions are ignored. + + .. admonition:: Debug Note + + In debug mode Flask will not tear down a request on an exception + immediately. Instead it will keep it alive so that the interactive + debugger can still access it. This behavior can be controlled + by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_appcontext(self, f): + """Registers a function to be called when the application context + ends. These functions are typically also called when the request + context is popped. + + Example:: + + ctx = app.app_context() + ctx.push() + ... + ctx.pop() + + When ``ctx.pop()`` is executed in the above example, the teardown + functions are called just before the app context moves from the + stack of active contexts. This becomes relevant if you are using + such constructs in tests. + + Since a request context typically also manages an application + context it would also be called when you pop a request context. + + When a teardown function was called because of an exception it will + be passed an error object. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def context_processor(self, f): + """Registers a template context processor function.""" + self.template_context_processors[None].append(f) + return f + + @setupmethod + def shell_context_processor(self, f): + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + @setupmethod + def url_value_preprocessor(self, f): + """Registers a function as URL value preprocessor for all view + functions of the application. It's called before the view functions + are called and can modify the url values provided. + """ + self.url_value_preprocessors.setdefault(None, []).append(f) + return f + + @setupmethod + def url_defaults(self, f): + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + """ + self.url_default_functions.setdefault(None, []).append(f) + return f + + def _find_error_handler(self, e): + """Finds a registered error handler for the request’s blueprint. + Otherwise falls back to the app, returns None if not a suitable + handler is found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + + def find_handler(handler_map): + if not handler_map: + return + for cls in exc_class.__mro__: + handler = handler_map.get(cls) + if handler is not None: + # cache for next time exc_class is raised + handler_map[exc_class] = handler + return handler + + # try blueprint handlers + handler = find_handler(self.error_handler_spec + .get(request.blueprint, {}) + .get(code)) + if handler is not None: + return handler + + # fall back to app handlers + return find_handler(self.error_handler_spec[None].get(code)) + + def handle_http_exception(self, e): + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionadded:: 0.3 + """ + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + + handler = self._find_error_handler(e) + if handler is None: + return e + return handler(e) + + def trap_http_exception(self, e): + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionadded:: 0.8 + """ + if self.config['TRAP_HTTP_EXCEPTIONS']: + return True + if self.config['TRAP_BAD_REQUEST_ERRORS']: + return isinstance(e, BadRequest) + return False + + def handle_user_exception(self, e): + """This method is called whenever an exception occurs that should be + handled. A special case are + :class:`~werkzeug.exception.HTTPException`\s which are forwarded by + this function to the :meth:`handle_http_exception` method. This + function will either return a response value or reraise the + exception with the same traceback. + + .. versionadded:: 0.7 + """ + exc_type, exc_value, tb = sys.exc_info() + assert exc_value is e + + # ensure not to trash sys.exc_info() at that point in case someone + # wants the traceback preserved in handle_http_exception. Of course + # we cannot prevent users from trashing it themselves in a custom + # trap_http_exception method so that's their fault then. + + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + handler = self._find_error_handler(e) + + if handler is None: + reraise(exc_type, exc_value, tb) + return handler(e) + + def handle_exception(self, e): + """Default exception handling that kicks in when an exception + occurs that is not caught. In debug mode the exception will + be re-raised immediately, otherwise it is logged and the handler + for a 500 internal server error is used. If no such handler + exists, a default 500 internal server error message is displayed. + + .. versionadded:: 0.3 + """ + exc_type, exc_value, tb = sys.exc_info() + + got_request_exception.send(self, exception=e) + handler = self._find_error_handler(InternalServerError()) + + if self.propagate_exceptions: + # if we want to repropagate the exception, we can attempt to + # raise it with the whole traceback in case we can do that + # (the function was actually called from the except part) + # otherwise, we just raise the error again + if exc_value is e: + reraise(exc_type, exc_value, tb) + else: + raise e + + self.log_exception((exc_type, exc_value, tb)) + if handler is None: + return InternalServerError() + return self.finalize_request(handler(e), from_error_handler=True) + + def log_exception(self, exc_info): + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error('Exception on %s [%s]' % ( + request.path, + request.method + ), exc_info=exc_info) + + def raise_routing_exception(self, request): + """Exceptions that are recording during routing are reraised with + this method. During debug we are not reraising redirect requests + for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising + a different error instead to help debug situations. + + :internal: + """ + if not self.debug \ + or not isinstance(request.routing_exception, RequestRedirect) \ + or request.method in ('GET', 'HEAD', 'OPTIONS'): + raise request.routing_exception + + from .debughelpers import FormDataRoutingRedirect + raise FormDataRoutingRedirect(request) + + def dispatch_request(self): + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = _request_ctx_stack.top.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule = req.url_rule + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if getattr(rule, 'provide_automatic_options', False) \ + and req.method == 'OPTIONS': + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + return self.view_functions[rule.endpoint](**req.view_args) + + def full_dispatch_request(self): + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self.try_trigger_before_first_request_functions() + try: + request_started.send(self) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + return self.finalize_request(rv) + + def finalize_request(self, rv, from_error_handler=False): + """Given the return value from a view function this finalizes + the request by converting it into a response and invoking the + postprocessing functions. This is invoked for both normal + request dispatching as well as error handlers. + + Because this means that it might be called as a result of a + failure a special safe mode is available which can be enabled + with the `from_error_handler` flag. If enabled, failures in + response processing will be logged and otherwise ignored. + + :internal: + """ + response = self.make_response(rv) + try: + response = self.process_response(response) + request_finished.send(self, response=response) + except Exception: + if not from_error_handler: + raise + self.logger.exception('Request finalizing failed with an ' + 'error while handling an error') + return response + + def try_trigger_before_first_request_functions(self): + """Called before each request and will ensure that it triggers + the :attr:`before_first_request_funcs` and only exactly once per + application instance (which means process usually). + + :internal: + """ + if self._got_first_request: + return + with self._before_request_lock: + if self._got_first_request: + return + for func in self.before_first_request_funcs: + func() + self._got_first_request = True + + def make_default_options_response(self): + """This method is called to create the default ``OPTIONS`` response. + This can be changed through subclassing to change the default + behavior of ``OPTIONS`` responses. + + .. versionadded:: 0.7 + """ + adapter = _request_ctx_stack.top.url_adapter + if hasattr(adapter, 'allowed_methods'): + methods = adapter.allowed_methods() + else: + # fallback for Werkzeug < 0.7 + methods = [] + try: + adapter.match(method='--') + except MethodNotAllowed as e: + methods = e.valid_methods + except HTTPException as e: + pass + rv = self.response_class() + rv.allow.update(methods) + return rv + + def should_ignore_error(self, error): + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def make_response(self, rv): + """Converts the return value from a view function to a real + response object that is an instance of :attr:`response_class`. + + The following types are allowed for `rv`: + + .. tabularcolumns:: |p{3.5cm}|p{9.5cm}| + + ======================= =========================================== + :attr:`response_class` the object is returned unchanged + :class:`str` a response object is created with the + string as body + :class:`unicode` a response object is created with the + string encoded to utf-8 as body + a WSGI function the function is called as WSGI application + and buffered as response object + :class:`tuple` A tuple in the form ``(response, status, + headers)`` or ``(response, headers)`` + where `response` is any of the + types defined here, `status` is a string + or an integer and `headers` is a list or + a dictionary with header values. + ======================= =========================================== + + :param rv: the return value from the view function + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + status_or_headers = headers = None + if isinstance(rv, tuple): + rv, status_or_headers, headers = rv + (None,) * (3 - len(rv)) + + if rv is None: + raise ValueError('View function did not return a response') + + if isinstance(status_or_headers, (dict, list)): + headers, status_or_headers = status_or_headers, None + + if not isinstance(rv, self.response_class): + # When we create a response object directly, we let the constructor + # set the headers and status. We do this because there can be + # some extra logic involved when creating these objects with + # specific values (like default content type selection). + if isinstance(rv, (text_type, bytes, bytearray)): + rv = self.response_class(rv, headers=headers, + status=status_or_headers) + headers = status_or_headers = None + else: + rv = self.response_class.force_type(rv, request.environ) + + if status_or_headers is not None: + if isinstance(status_or_headers, string_types): + rv.status = status_or_headers + else: + rv.status_code = status_or_headers + if headers: + rv.headers.extend(headers) + + return rv + + def create_url_adapter(self, request): + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set up + so the request is passed explicitly. + + .. versionadded:: 0.6 + + .. versionchanged:: 0.9 + This can now also be called without a request object when the + URL adapter is created for the application context. + """ + if request is not None: + return self.url_map.bind_to_environ(request.environ, + server_name=self.config['SERVER_NAME']) + # We need at the very least the server name to be set for this + # to work. + if self.config['SERVER_NAME'] is not None: + return self.url_map.bind( + self.config['SERVER_NAME'], + script_name=self.config['APPLICATION_ROOT'] or '/', + url_scheme=self.config['PREFERRED_URL_SCHEME']) + + def inject_url_defaults(self, endpoint, values): + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + funcs = self.url_default_functions.get(None, ()) + if '.' in endpoint: + bp = endpoint.rsplit('.', 1)[0] + funcs = chain(funcs, self.url_default_functions.get(bp, ())) + for func in funcs: + func(endpoint, values) + + def handle_url_build_error(self, error, endpoint, values): + """Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`. + """ + exc_type, exc_value, tb = sys.exc_info() + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + if rv is not None: + return rv + except BuildError as e: + # make error available outside except block (py3) + error = e + + # At this point we want to reraise the exception. If the error is + # still the same one we can reraise it with the original traceback, + # otherwise we raise it from here. + if error is exc_value: + reraise(exc_type, exc_value, tb) + raise error + + def preprocess_request(self): + """Called before the actual request dispatching and will + call each :meth:`before_request` decorated function, passing no + arguments. + If any of these functions returns a value, it's handled as + if it was the return value from the view and further + request handling is stopped. + + This also triggers the :meth:`url_value_preprocessor` functions before + the actual :meth:`before_request` functions are called. + """ + bp = _request_ctx_stack.top.request.blueprint + + funcs = self.url_value_preprocessors.get(None, ()) + if bp is not None and bp in self.url_value_preprocessors: + funcs = chain(funcs, self.url_value_preprocessors[bp]) + for func in funcs: + func(request.endpoint, request.view_args) + + funcs = self.before_request_funcs.get(None, ()) + if bp is not None and bp in self.before_request_funcs: + funcs = chain(funcs, self.before_request_funcs[bp]) + for func in funcs: + rv = func() + if rv is not None: + return rv + + def process_response(self, response): + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = _request_ctx_stack.top + bp = ctx.request.blueprint + funcs = ctx._after_request_functions + if bp is not None and bp in self.after_request_funcs: + funcs = chain(funcs, reversed(self.after_request_funcs[bp])) + if None in self.after_request_funcs: + funcs = chain(funcs, reversed(self.after_request_funcs[None])) + for handler in funcs: + response = handler(response) + if not self.session_interface.is_null_session(ctx.session): + self.save_session(ctx.session, response) + return response + + def do_teardown_request(self, exc=_sentinel): + """Called after the actual request dispatching and will + call every as :meth:`teardown_request` decorated function. This is + not actually called by the :class:`Flask` object itself but is always + triggered when the request context is popped. That way we have a + tighter control over certain resources under testing environments. + + .. versionchanged:: 0.9 + Added the `exc` argument. Previously this was always using the + current exception information. + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + funcs = reversed(self.teardown_request_funcs.get(None, ())) + bp = _request_ctx_stack.top.request.blueprint + if bp is not None and bp in self.teardown_request_funcs: + funcs = chain(funcs, reversed(self.teardown_request_funcs[bp])) + for func in funcs: + func(exc) + request_tearing_down.send(self, exc=exc) + + def do_teardown_appcontext(self, exc=_sentinel): + """Called when an application context is popped. This works pretty + much the same as :meth:`do_teardown_request` but for the application + context. + + .. versionadded:: 0.9 + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + for func in reversed(self.teardown_appcontext_funcs): + func(exc) + appcontext_tearing_down.send(self, exc=exc) + + def app_context(self): + """Binds the application only. For as long as the application is bound + to the current context the :data:`flask.current_app` points to that + application. An application context is automatically created when a + request context is pushed if necessary. + + Example usage:: + + with app.app_context(): + ... + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ): + """Creates a :class:`~flask.ctx.RequestContext` from the given + environment and binds it to the current context. This must be used in + combination with the ``with`` statement because the request is only bound + to the current context for the duration of the ``with`` block. + + Example usage:: + + with app.request_context(environ): + do_something_with(request) + + The object returned can also be used without the ``with`` statement + which is useful for working in the shell. The example above is + doing exactly the same as this code:: + + ctx = app.request_context(environ) + ctx.push() + try: + do_something_with(request) + finally: + ctx.pop() + + .. versionchanged:: 0.3 + Added support for non-with statement usage and ``with`` statement + is now passed the ctx object. + + :param environ: a WSGI environment + """ + return RequestContext(self, environ) + + def test_request_context(self, *args, **kwargs): + """Creates a WSGI environment from the given values (see + :class:`werkzeug.test.EnvironBuilder` for more information, this + function accepts the same arguments). + """ + from flask.testing import make_test_environ_builder + builder = make_test_environ_builder(self, *args, **kwargs) + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app(self, environ, start_response): + """The actual WSGI application. This is not implemented in + `__call__` so that middlewares can be applied without losing a + reference to the class. So instead of doing this:: + + app = MyMiddleware(app) + + It's a better idea to do this instead:: + + app.wsgi_app = MyMiddleware(app.wsgi_app) + + Then you still have the original application object around and + can continue to call methods on it. + + .. versionchanged:: 0.7 + The behavior of the before and after request callbacks was changed + under error conditions and a new callback was added that will + always execute at the end of the request, independent on if an + error occurred or not. See :ref:`callbacks-and-errors`. + + :param environ: a WSGI environment + :param start_response: a callable accepting a status code, + a list of headers and an optional + exception context to start the response + """ + ctx = self.request_context(environ) + ctx.push() + error = None + try: + try: + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.handle_exception(e) + except: + error = sys.exc_info()[1] + raise + return response(environ, start_response) + finally: + if self.should_ignore_error(error): + error = None + ctx.auto_pop(error) + + def __call__(self, environ, start_response): + """Shortcut for :attr:`wsgi_app`.""" + return self.wsgi_app(environ, start_response) + + def __repr__(self): + return '<%s %r>' % ( + self.__class__.__name__, + self.name, + ) diff --git a/venv/lib/python2.7/site-packages/flask/app.pyc b/venv/lib/python2.7/site-packages/flask/app.pyc new file mode 100644 index 0000000..0fe4cc1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/app.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/blueprints.py b/venv/lib/python2.7/site-packages/flask/blueprints.py new file mode 100644 index 0000000..586a1b0 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/blueprints.py @@ -0,0 +1,413 @@ +# -*- coding: utf-8 -*- +""" + flask.blueprints + ~~~~~~~~~~~~~~~~ + + Blueprints are the recommended way to implement larger or more + pluggable applications in Flask 0.7 and later. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +from functools import update_wrapper + +from .helpers import _PackageBoundObject, _endpoint_from_view_func + + +class BlueprintSetupState(object): + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__(self, blueprint, app, options, first_registration): + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get('subdomain') + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get('url_prefix') + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get('url_defaults', ())) + + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix: + rule = self.url_prefix + rule + options.setdefault('subdomain', self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) + defaults = self.url_defaults + if 'defaults' in options: + defaults = dict(defaults, **options.pop('defaults')) + self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint), + view_func, defaults=defaults, **options) + + +class Blueprint(_PackageBoundObject): + """Represents a blueprint. A blueprint is an object that records + functions that will be called with the + :class:`~flask.blueprints.BlueprintSetupState` later to register functions + or other things on the main application. See :ref:`blueprints` for more + information. + + .. versionadded:: 0.7 + """ + + warn_on_modifications = False + _got_registered_once = False + + def __init__(self, name, import_name, static_folder=None, + static_url_path=None, template_folder=None, + url_prefix=None, subdomain=None, url_defaults=None, + root_path=None): + _PackageBoundObject.__init__(self, import_name, template_folder, + root_path=root_path) + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.static_folder = static_folder + self.static_url_path = static_url_path + self.deferred_functions = [] + if url_defaults is None: + url_defaults = {} + self.url_values_defaults = url_defaults + + def record(self, func): + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + if self._got_registered_once and self.warn_on_modifications: + from warnings import warn + warn(Warning('The blueprint was already registered once ' + 'but is getting modified now. These changes ' + 'will not show up.')) + self.deferred_functions.append(func) + + def record_once(self, func): + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + def wrapper(state): + if state.first_registration: + func(state) + return self.record(update_wrapper(wrapper, func)) + + def make_setup_state(self, app, options, first_registration=False): + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + def register(self, app, options, first_registration=False): + """Called by :meth:`Flask.register_blueprint` to register a blueprint + on the application. This can be overridden to customize the register + behavior. Keyword arguments from + :func:`~flask.Flask.register_blueprint` are directly forwarded to this + method in the `options` dictionary. + """ + self._got_registered_once = True + state = self.make_setup_state(app, options, first_registration) + if self.has_static_folder: + state.add_url_rule(self.static_url_path + '/', + view_func=self.send_static_file, + endpoint='static') + + for deferred in self.deferred_functions: + deferred(state) + + def route(self, rule, **options): + """Like :meth:`Flask.route` but for a blueprint. The endpoint for the + :func:`url_for` function is prefixed with the name of the blueprint. + """ + def decorator(f): + endpoint = options.pop("endpoint", f.__name__) + self.add_url_rule(rule, endpoint, f, **options) + return f + return decorator + + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for + the :func:`url_for` function is prefixed with the name of the blueprint. + """ + if endpoint: + assert '.' not in endpoint, "Blueprint endpoints should not contain dots" + self.record(lambda s: + s.add_url_rule(rule, endpoint, view_func, **options)) + + def endpoint(self, endpoint): + """Like :meth:`Flask.endpoint` but for a blueprint. This does not + prefix the endpoint with the blueprint name, this has to be done + explicitly by the user of this method. If the endpoint is prefixed + with a `.` it will be registered to the current blueprint, otherwise + it's an application independent endpoint. + """ + def decorator(f): + def register_endpoint(state): + state.app.view_functions[endpoint] = f + self.record_once(register_endpoint) + return f + return decorator + + def app_template_filter(self, name=None): + """Register a custom template filter, available application wide. Like + :meth:`Flask.template_filter` but for a blueprint. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_filter(f, name=name) + return f + return decorator + + def add_app_template_filter(self, f, name=None): + """Register a custom template filter, available application wide. Like + :meth:`Flask.add_template_filter` but for a blueprint. Works exactly + like the :meth:`app_template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.filters[name or f.__name__] = f + self.record_once(register_template) + + def app_template_test(self, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.template_test` but for a blueprint. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_test(f, name=name) + return f + return decorator + + def add_app_template_test(self, f, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.add_template_test` but for a blueprint. Works exactly + like the :meth:`app_template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.tests[name or f.__name__] = f + self.record_once(register_template) + + def app_template_global(self, name=None): + """Register a custom template global, available application wide. Like + :meth:`Flask.template_global` but for a blueprint. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_global(f, name=name) + return f + return decorator + + def add_app_template_global(self, f, name=None): + """Register a custom template global, available application wide. Like + :meth:`Flask.add_template_global` but for a blueprint. Works exactly + like the :meth:`app_template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.globals[name or f.__name__] = f + self.record_once(register_template) + + def before_request(self, f): + """Like :meth:`Flask.before_request` but for a blueprint. This function + is only executed before each request that is handled by a function of + that blueprint. + """ + self.record_once(lambda s: s.app.before_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def before_app_request(self, f): + """Like :meth:`Flask.before_request`. Such a function is executed + before each request, even if outside of a blueprint. + """ + self.record_once(lambda s: s.app.before_request_funcs + .setdefault(None, []).append(f)) + return f + + def before_app_first_request(self, f): + """Like :meth:`Flask.before_first_request`. Such a function is + executed before the first request to the application. + """ + self.record_once(lambda s: s.app.before_first_request_funcs.append(f)) + return f + + def after_request(self, f): + """Like :meth:`Flask.after_request` but for a blueprint. This function + is only executed after each request that is handled by a function of + that blueprint. + """ + self.record_once(lambda s: s.app.after_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def after_app_request(self, f): + """Like :meth:`Flask.after_request` but for a blueprint. Such a function + is executed after each request, even if outside of the blueprint. + """ + self.record_once(lambda s: s.app.after_request_funcs + .setdefault(None, []).append(f)) + return f + + def teardown_request(self, f): + """Like :meth:`Flask.teardown_request` but for a blueprint. This + function is only executed when tearing down requests handled by a + function of that blueprint. Teardown request functions are executed + when the request context is popped, even when no actual request was + performed. + """ + self.record_once(lambda s: s.app.teardown_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def teardown_app_request(self, f): + """Like :meth:`Flask.teardown_request` but for a blueprint. Such a + function is executed when tearing down each request, even if outside of + the blueprint. + """ + self.record_once(lambda s: s.app.teardown_request_funcs + .setdefault(None, []).append(f)) + return f + + def context_processor(self, f): + """Like :meth:`Flask.context_processor` but for a blueprint. This + function is only executed for requests handled by a blueprint. + """ + self.record_once(lambda s: s.app.template_context_processors + .setdefault(self.name, []).append(f)) + return f + + def app_context_processor(self, f): + """Like :meth:`Flask.context_processor` but for a blueprint. Such a + function is executed each request, even if outside of the blueprint. + """ + self.record_once(lambda s: s.app.template_context_processors + .setdefault(None, []).append(f)) + return f + + def app_errorhandler(self, code): + """Like :meth:`Flask.errorhandler` but for a blueprint. This + handler is used for all requests, even if outside of the blueprint. + """ + def decorator(f): + self.record_once(lambda s: s.app.errorhandler(code)(f)) + return f + return decorator + + def url_value_preprocessor(self, f): + """Registers a function as URL value preprocessor for this + blueprint. It's called before the view functions are called and + can modify the url values provided. + """ + self.record_once(lambda s: s.app.url_value_preprocessors + .setdefault(self.name, []).append(f)) + return f + + def url_defaults(self, f): + """Callback function for URL defaults for this blueprint. It's called + with the endpoint and values and should update the values passed + in place. + """ + self.record_once(lambda s: s.app.url_default_functions + .setdefault(self.name, []).append(f)) + return f + + def app_url_value_preprocessor(self, f): + """Same as :meth:`url_value_preprocessor` but application wide. + """ + self.record_once(lambda s: s.app.url_value_preprocessors + .setdefault(None, []).append(f)) + return f + + def app_url_defaults(self, f): + """Same as :meth:`url_defaults` but application wide. + """ + self.record_once(lambda s: s.app.url_default_functions + .setdefault(None, []).append(f)) + return f + + def errorhandler(self, code_or_exception): + """Registers an error handler that becomes active for this blueprint + only. Please be aware that routing does not happen local to a + blueprint so an error handler for 404 usually is not handled by + a blueprint unless it is caused inside a view function. Another + special case is the 500 internal server error which is always looked + up from the application. + + Otherwise works as the :meth:`~flask.Flask.errorhandler` decorator + of the :class:`~flask.Flask` object. + """ + def decorator(f): + self.record_once(lambda s: s.app._register_error_handler( + self.name, code_or_exception, f)) + return f + return decorator + + def register_error_handler(self, code_or_exception, f): + """Non-decorator version of the :meth:`errorhandler` error attach + function, akin to the :meth:`~flask.Flask.register_error_handler` + application-wide function of the :class:`~flask.Flask` object but + for error handlers limited to this blueprint. + + .. versionadded:: 0.11 + """ + self.record_once(lambda s: s.app._register_error_handler( + self.name, code_or_exception, f)) diff --git a/venv/lib/python2.7/site-packages/flask/blueprints.pyc b/venv/lib/python2.7/site-packages/flask/blueprints.pyc new file mode 100644 index 0000000..91182fb Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/blueprints.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/cli.py b/venv/lib/python2.7/site-packages/flask/cli.py new file mode 100644 index 0000000..074ee76 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/cli.py @@ -0,0 +1,517 @@ +# -*- coding: utf-8 -*- +""" + flask.cli + ~~~~~~~~~ + + A simple command line application to run flask apps. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +import os +import sys +from threading import Lock, Thread +from functools import update_wrapper + +import click + +from ._compat import iteritems, reraise +from .helpers import get_debug_flag +from . import __version__ + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(module): + """Given a module instance this tries to find the best possible + application in the module or raises an exception. + """ + from . import Flask + + # Search for the most common names first. + for attr_name in 'app', 'application': + app = getattr(module, attr_name, None) + if app is not None and isinstance(app, Flask): + return app + + # Otherwise find the only object that is a Flask instance. + matches = [v for k, v in iteritems(module.__dict__) + if isinstance(v, Flask)] + + if len(matches) == 1: + return matches[0] + raise NoAppException('Failed to find application in module "%s". Are ' + 'you sure it contains a Flask application? Maybe ' + 'you wrapped it in a WSGI middleware or you are ' + 'using a factory function.' % module.__name__) + + +def prepare_exec_for_file(filename): + """Given a filename this will try to calculate the python path, add it + to the search path and return the actual module name that is expected. + """ + module = [] + + # Chop off file extensions or package markers + if os.path.split(filename)[1] == '__init__.py': + filename = os.path.dirname(filename) + elif filename.endswith('.py'): + filename = filename[:-3] + else: + raise NoAppException('The file provided (%s) does exist but is not a ' + 'valid Python file. This means that it cannot ' + 'be used as application. Please change the ' + 'extension to .py' % filename) + filename = os.path.realpath(filename) + + dirpath = filename + while 1: + dirpath, extra = os.path.split(dirpath) + module.append(extra) + if not os.path.isfile(os.path.join(dirpath, '__init__.py')): + break + + sys.path.insert(0, dirpath) + return '.'.join(module[::-1]) + + +def locate_app(app_id): + """Attempts to locate the application.""" + __traceback_hide__ = True + if ':' in app_id: + module, app_obj = app_id.split(':', 1) + else: + module = app_id + app_obj = None + + try: + __import__(module) + except ImportError: + # Reraise the ImportError if it occurred within the imported module. + # Determine this by checking whether the trace has a depth > 1. + if sys.exc_info()[-1].tb_next: + raise + else: + raise NoAppException('The file/path provided (%s) does not appear' + ' to exist. Please verify the path is ' + 'correct. If app is not on PYTHONPATH, ' + 'ensure the extension is .py' % module) + + mod = sys.modules[module] + if app_obj is None: + app = find_best_app(mod) + else: + app = getattr(mod, app_obj, None) + if app is None: + raise RuntimeError('Failed to find application in module "%s"' + % module) + + return app + + +def find_default_import_path(): + app = os.environ.get('FLASK_APP') + if app is None: + return + if os.path.isfile(app): + return prepare_exec_for_file(app) + return app + + +def get_version(ctx, param, value): + if not value or ctx.resilient_parsing: + return + message = 'Flask %(version)s\nPython %(python_version)s' + click.echo(message % { + 'version': __version__, + 'python_version': sys.version, + }, color=ctx.color) + ctx.exit() + +version_option = click.Option(['--version'], + help='Show the flask version', + expose_value=False, + callback=get_version, + is_flag=True, is_eager=True) + +class DispatchingApp(object): + """Special application that dispatches to a Flask application which + is imported by name in a background thread. If an error happens + it is recorded and shown as part of the WSGI handling which in case + of the Werkzeug debugger means that it shows up in the browser. + """ + + def __init__(self, loader, use_eager_loading=False): + self.loader = loader + self._app = None + self._lock = Lock() + self._bg_loading_exc_info = None + if use_eager_loading: + self._load_unlocked() + else: + self._load_in_background() + + def _load_in_background(self): + def _load_app(): + __traceback_hide__ = True + with self._lock: + try: + self._load_unlocked() + except Exception: + self._bg_loading_exc_info = sys.exc_info() + t = Thread(target=_load_app, args=()) + t.start() + + def _flush_bg_loading_exception(self): + __traceback_hide__ = True + exc_info = self._bg_loading_exc_info + if exc_info is not None: + self._bg_loading_exc_info = None + reraise(*exc_info) + + def _load_unlocked(self): + __traceback_hide__ = True + self._app = rv = self.loader() + self._bg_loading_exc_info = None + return rv + + def __call__(self, environ, start_response): + __traceback_hide__ = True + if self._app is not None: + return self._app(environ, start_response) + self._flush_bg_loading_exception() + with self._lock: + if self._app is not None: + rv = self._app + else: + rv = self._load_unlocked() + return rv(environ, start_response) + + +class ScriptInfo(object): + """Help object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + """ + + def __init__(self, app_import_path=None, create_app=None): + if create_app is None: + if app_import_path is None: + app_import_path = find_default_import_path() + self.app_import_path = app_import_path + else: + app_import_path = None + + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data = {} + self._loaded_app = None + + def load_app(self): + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + __traceback_hide__ = True + if self._loaded_app is not None: + return self._loaded_app + if self.create_app is not None: + rv = self.create_app(self) + else: + if not self.app_import_path: + raise NoAppException( + 'Could not locate Flask application. You did not provide ' + 'the FLASK_APP environment variable.\n\nFor more ' + 'information see ' + 'http://flask.pocoo.org/docs/latest/quickstart/') + rv = locate_app(self.app_import_path) + debug = get_debug_flag() + if debug is not None: + rv.debug = debug + self._loaded_app = rv + return rv + + +pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) + + +def with_appcontext(f): + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. If callbacks are registered directly + to the ``app.cli`` object then they are wrapped with this function + by default unless it's disabled. + """ + @click.pass_context + def decorator(__ctx, *args, **kwargs): + with __ctx.ensure_object(ScriptInfo).load_app().app_context(): + return __ctx.invoke(f, *args, **kwargs) + return update_wrapper(decorator, f) + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + + Not to be confused with :class:`FlaskGroup`. + """ + + def command(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop('with_appcontext', True) + def decorator(f): + if wrap_for_ctx: + f = with_appcontext(f) + return click.Group.command(self, *args, **kwargs)(f) + return decorator + + def group(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault('cls', AppGroup) + return click.Group.group(self, *args, **kwargs) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. + + For information as of why this is useful see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands wil be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info + and returns the loaded app. + """ + + def __init__(self, add_default_commands=True, create_app=None, + add_version_option=True, **extra): + params = list(extra.pop('params', None) or ()) + + if add_version_option: + params.append(version_option) + + AppGroup.__init__(self, params=params, **extra) + self.create_app = create_app + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self): + if self._loaded_plugin_commands: + return + try: + import pkg_resources + except ImportError: + self._loaded_plugin_commands = True + return + + for ep in pkg_resources.iter_entry_points('flask.commands'): + self.add_command(ep.load(), ep.name) + self._loaded_plugin_commands = True + + def get_command(self, ctx, name): + self._load_plugin_commands() + + # We load built-in commands first as these should always be the + # same no matter what the app does. If the app does want to + # override this it needs to make a custom instance of this group + # and not attach the default commands. + # + # This also means that the script stays functional in case the + # application completely fails. + rv = AppGroup.get_command(self, ctx, name) + if rv is not None: + return rv + + info = ctx.ensure_object(ScriptInfo) + try: + rv = info.load_app().cli.get_command(ctx, name) + if rv is not None: + return rv + except NoAppException: + pass + + def list_commands(self, ctx): + self._load_plugin_commands() + + # The commands available is the list of both the application (if + # available) plus the builtin commands. + rv = set(click.Group.list_commands(self, ctx)) + info = ctx.ensure_object(ScriptInfo) + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except Exception: + # Here we intentionally swallow all exceptions as we don't + # want the help page to break if the app does not exist. + # If someone attempts to use the command we try to create + # the app again and this will give us the error. + pass + return sorted(rv) + + def main(self, *args, **kwargs): + obj = kwargs.get('obj') + if obj is None: + obj = ScriptInfo(create_app=self.create_app) + kwargs['obj'] = obj + kwargs.setdefault('auto_envvar_prefix', 'FLASK') + return AppGroup.main(self, *args, **kwargs) + + +@click.command('run', short_help='Runs a development server.') +@click.option('--host', '-h', default='127.0.0.1', + help='The interface to bind to.') +@click.option('--port', '-p', default=5000, + help='The port to bind to.') +@click.option('--reload/--no-reload', default=None, + help='Enable or disable the reloader. By default the reloader ' + 'is active if debug is enabled.') +@click.option('--debugger/--no-debugger', default=None, + help='Enable or disable the debugger. By default the debugger ' + 'is active if debug is enabled.') +@click.option('--eager-loading/--lazy-loader', default=None, + help='Enable or disable eager loading. By default eager ' + 'loading is enabled if the reloader is disabled.') +@click.option('--with-threads/--without-threads', default=False, + help='Enable or disable multithreading.') +@pass_script_info +def run_command(info, host, port, reload, debugger, eager_loading, + with_threads): + """Runs a local development server for the Flask application. + + This local server is recommended for development purposes only but it + can also be used for simple intranet deployments. By default it will + not support any sort of concurrency at all to simplify debugging. This + can be changed with the --with-threads option which will enable basic + multithreading. + + The reloader and debugger are by default enabled if the debug flag of + Flask is enabled and disabled otherwise. + """ + from werkzeug.serving import run_simple + + debug = get_debug_flag() + if reload is None: + reload = bool(debug) + if debugger is None: + debugger = bool(debug) + if eager_loading is None: + eager_loading = not reload + + app = DispatchingApp(info.load_app, use_eager_loading=eager_loading) + + # Extra startup messages. This depends a bit on Werkzeug internals to + # not double execute when the reloader kicks in. + if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': + # If we have an import path we can print it out now which can help + # people understand what's being served. If we do not have an + # import path because the app was loaded through a callback then + # we won't print anything. + if info.app_import_path is not None: + print(' * Serving Flask app "%s"' % info.app_import_path) + if debug is not None: + print(' * Forcing debug mode %s' % (debug and 'on' or 'off')) + + run_simple(host, port, app, use_reloader=reload, + use_debugger=debugger, threaded=with_threads) + + +@click.command('shell', short_help='Runs a shell in the app context.') +@with_appcontext +def shell_command(): + """Runs an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to it's configuration. + + This is useful for executing small snippets of management code + without having to manually configuring the application. + """ + import code + from flask.globals import _app_ctx_stack + app = _app_ctx_stack.top.app + banner = 'Python %s on %s\nApp: %s%s\nInstance: %s' % ( + sys.version, + sys.platform, + app.import_name, + app.debug and ' [debug]' or '', + app.instance_path, + ) + ctx = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get('PYTHONSTARTUP') + if startup and os.path.isfile(startup): + with open(startup, 'r') as f: + eval(compile(f.read(), startup, 'exec'), ctx) + + ctx.update(app.make_shell_context()) + + code.interact(banner=banner, local=ctx) + + +cli = FlaskGroup(help="""\ +This shell command acts as general utility script for Flask applications. + +It loads the application configured (through the FLASK_APP environment +variable) and then provides commands either provided by the application or +Flask itself. + +The most useful commands are the "run" and "shell" command. + +Example usage: + +\b + %(prefix)s%(cmd)s FLASK_APP=hello.py + %(prefix)s%(cmd)s FLASK_DEBUG=1 + %(prefix)sflask run +""" % { + 'cmd': os.name == 'posix' and 'export' or 'set', + 'prefix': os.name == 'posix' and '$ ' or '', +}) + + +def main(as_module=False): + this_module = __package__ + '.cli' + args = sys.argv[1:] + + if as_module: + if sys.version_info >= (2, 7): + name = 'python -m ' + this_module.rsplit('.', 1)[0] + else: + name = 'python -m ' + this_module + + # This module is always executed as "python -m flask.run" and as such + # we need to ensure that we restore the actual command line so that + # the reloader can properly operate. + sys.argv = ['-m', this_module] + sys.argv[1:] + else: + name = None + + cli.main(args=args, prog_name=name) + + +if __name__ == '__main__': + main(as_module=True) diff --git a/venv/lib/python2.7/site-packages/flask/cli.pyc b/venv/lib/python2.7/site-packages/flask/cli.pyc new file mode 100644 index 0000000..5b76a0f Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/cli.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/config.py b/venv/lib/python2.7/site-packages/flask/config.py new file mode 100644 index 0000000..697add7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/config.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +""" + flask.config + ~~~~~~~~~~~~ + + Implements the configuration related objects. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +import os +import types +import errno + +from werkzeug.utils import import_string +from ._compat import string_types, iteritems +from . import json + + +class ConfigAttribute(object): + """Makes an attribute forward to the config""" + + def __init__(self, name, get_converter=None): + self.__name__ = name + self.get_converter = get_converter + + def __get__(self, obj, type=None): + if obj is None: + return self + rv = obj.config[self.__name__] + if self.get_converter is not None: + rv = self.get_converter(rv) + return rv + + def __set__(self, obj, value): + obj.config[self.__name__] = value + + +class Config(dict): + """Works exactly like a dict but provides ways to fill it from files + or special dictionaries. There are two common patterns to populate the + config. + + Either you can fill the config from a config file:: + + app.config.from_pyfile('yourconfig.cfg') + + Or alternatively you can define the configuration options in the + module that calls :meth:`from_object` or provide an import path to + a module that should be loaded. It is also possible to tell it to + use the same module and with that provide the configuration values + just before the call:: + + DEBUG = True + SECRET_KEY = 'development key' + app.config.from_object(__name__) + + In both cases (loading from any Python file or loading from modules), + only uppercase keys are added to the config. This makes it possible to use + lowercase values in the config file for temporary values that are not added + to the config or to define the config keys in the same file that implements + the application. + + Probably the most interesting way to load configurations is from an + environment variable pointing to a file:: + + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + + In this case before launching the application you have to set this + environment variable to the file you want to use. On Linux and OS X + use the export statement:: + + export YOURAPPLICATION_SETTINGS='/path/to/config/file' + + On windows use `set` instead. + + :param root_path: path to which files are read relative from. When the + config object is created by the application, this is + the application's :attr:`~flask.Flask.root_path`. + :param defaults: an optional dictionary of default values + """ + + def __init__(self, root_path, defaults=None): + dict.__init__(self, defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name, silent=False): + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: bool. ``True`` if able to load config, ``False`` otherwise. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError('The environment variable %r is not set ' + 'and as such configuration could not be ' + 'loaded. Set this variable and make it ' + 'point to a configuration file' % + variable_name) + return self.from_pyfile(rv, silent=silent) + + def from_pyfile(self, filename, silent=False): + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType('config') + d.__file__ = filename + try: + with open(filename, mode='rb') as config_file: + exec(compile(config_file.read(), filename, 'exec'), d.__dict__) + except IOError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + e.strerror = 'Unable to load configuration file (%s)' % e.strerror + raise + self.from_object(d) + return True + + def from_object(self, obj): + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, string_types): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_json(self, filename, silent=False): + """Updates the values in the config from a JSON file. This function + behaves as if the JSON object was a dictionary and passed to the + :meth:`from_mapping` function. + + :param filename: the filename of the JSON file. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + + .. versionadded:: 0.11 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename) as json_file: + obj = json.loads(json_file.read()) + except IOError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + e.strerror = 'Unable to load configuration file (%s)' % e.strerror + raise + return self.from_mapping(obj) + + def from_mapping(self, *mapping, **kwargs): + """Updates the config like :meth:`update` ignoring items with non-upper + keys. + + .. versionadded:: 0.11 + """ + mappings = [] + if len(mapping) == 1: + if hasattr(mapping[0], 'items'): + mappings.append(mapping[0].items()) + else: + mappings.append(mapping[0]) + elif len(mapping) > 1: + raise TypeError( + 'expected at most 1 positional argument, got %d' % len(mapping) + ) + mappings.append(kwargs.items()) + for mapping in mappings: + for (key, value) in mapping: + if key.isupper(): + self[key] = value + return True + + def get_namespace(self, namespace, lowercase=True, trim_namespace=True): + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in iteritems(self): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace):] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self): + return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self)) diff --git a/venv/lib/python2.7/site-packages/flask/config.pyc b/venv/lib/python2.7/site-packages/flask/config.pyc new file mode 100644 index 0000000..6bb60f0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/config.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/ctx.py b/venv/lib/python2.7/site-packages/flask/ctx.py new file mode 100644 index 0000000..480d9c5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/ctx.py @@ -0,0 +1,410 @@ +# -*- coding: utf-8 -*- +""" + flask.ctx + ~~~~~~~~~ + + Implements the objects required to keep the context. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +import sys +from functools import update_wrapper + +from werkzeug.exceptions import HTTPException + +from .globals import _request_ctx_stack, _app_ctx_stack +from .signals import appcontext_pushed, appcontext_popped +from ._compat import BROKEN_PYPY_CTXMGR_EXIT, reraise + + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +class _AppCtxGlobals(object): + """A plain object.""" + + def get(self, name, default=None): + return self.__dict__.get(name, default) + + def pop(self, name, default=_sentinel): + if default is _sentinel: + return self.__dict__.pop(name) + else: + return self.__dict__.pop(name, default) + + def setdefault(self, name, default=None): + return self.__dict__.setdefault(name, default) + + def __contains__(self, item): + return item in self.__dict__ + + def __iter__(self): + return iter(self.__dict__) + + def __repr__(self): + top = _app_ctx_stack.top + if top is not None: + return '' % top.app.name + return object.__repr__(self) + + +def after_this_request(f): + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + _request_ctx_stack.top._after_request_functions.append(f) + return f + + +def copy_current_request_context(f): + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request like you + # would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + top = _request_ctx_stack.top + if top is None: + raise RuntimeError('This decorator can only be used at local scopes ' + 'when a request context is on the stack. For instance within ' + 'view functions.') + reqctx = top.copy() + def wrapper(*args, **kwargs): + with reqctx: + return f(*args, **kwargs) + return update_wrapper(wrapper, f) + + +def has_request_context(): + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g` for truthness):: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _request_ctx_stack.top is not None + + +def has_app_context(): + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _app_ctx_stack.top is not None + + +class AppContext(object): + """The application context binds an application object implicitly + to the current thread or greenlet, similar to how the + :class:`RequestContext` binds request information. The application + context is also implicitly created if a request context is created + but the application is not on top of the individual application + context. + """ + + def __init__(self, app): + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g = app.app_ctx_globals_class() + + # Like request context, app contexts can be pushed multiple times + # but there a basic "refcount" is enough to track them. + self._refcnt = 0 + + def push(self): + """Binds the app context to the current context.""" + self._refcnt += 1 + if hasattr(sys, 'exc_clear'): + sys.exc_clear() + _app_ctx_stack.push(self) + appcontext_pushed.send(self.app) + + def pop(self, exc=_sentinel): + """Pops the app context.""" + try: + self._refcnt -= 1 + if self._refcnt <= 0: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + rv = _app_ctx_stack.pop() + assert rv is self, 'Popped wrong app context. (%r instead of %r)' \ + % (rv, self) + appcontext_popped.send(self.app) + + def __enter__(self): + self.push() + return self + + def __exit__(self, exc_type, exc_value, tb): + self.pop(exc_value) + + if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: + reraise(exc_type, exc_value, tb) + + +class RequestContext(object): + """The request context contains all request relevant information. It is + created at the beginning of the request and pushed to the + `_request_ctx_stack` and removed at the end of it. It will create the + URL adapter and request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the request + for you. In debug mode the request context is kept around if + exceptions happen so that interactive debuggers have a chance to + introspect the data. With 0.4 this can also be forced for requests + that did not fail and outside of ``DEBUG`` mode. By setting + ``'flask._preserve_context'`` to ``True`` on the WSGI environment the + context will not pop itself at the end of the request. This is used by + the :meth:`~flask.Flask.test_client` for example to implement the + deferred cleanup functionality. + + You might find this helpful for unittests where you need the + information from the context local around for a little longer. Make + sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in + that situation, otherwise your unittests will leak memory. + """ + + def __init__(self, app, environ, request=None): + self.app = app + if request is None: + request = app.request_class(environ) + self.request = request + self.url_adapter = app.create_url_adapter(self.request) + self.flashes = None + self.session = None + + # Request contexts can be pushed multiple times and interleaved with + # other request contexts. Now only if the last level is popped we + # get rid of them. Additionally if an application context is missing + # one is created implicitly so for each level we add this information + self._implicit_app_ctx_stack = [] + + # indicator if the context was preserved. Next time another context + # is pushed the preserved context is popped. + self.preserved = False + + # remembers the exception for pop if there is one in case the context + # preservation kicks in. + self._preserved_exc = None + + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions = [] + + self.match_request() + + def _get_g(self): + return _app_ctx_stack.top.g + def _set_g(self, value): + _app_ctx_stack.top.g = value + g = property(_get_g, _set_g) + del _get_g, _set_g + + def copy(self): + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + """ + return self.__class__(self.app, + environ=self.request.environ, + request=self.request + ) + + def match_request(self): + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + url_rule, self.request.view_args = \ + self.url_adapter.match(return_rule=True) + self.request.url_rule = url_rule + except HTTPException as e: + self.request.routing_exception = e + + def push(self): + """Binds the request context to the current context.""" + # If an exception occurs in debug mode or if context preservation is + # activated under exception situations exactly one context stays + # on the stack. The rationale is that you want to access that + # information under debug situations. However if someone forgets to + # pop that context again we want to make sure that on the next push + # it's invalidated, otherwise we run at risk that something leaks + # memory. This is usually only a problem in test suite since this + # functionality is not active in production environments. + top = _request_ctx_stack.top + if top is not None and top.preserved: + top.pop(top._preserved_exc) + + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _app_ctx_stack.top + if app_ctx is None or app_ctx.app != self.app: + app_ctx = self.app.app_context() + app_ctx.push() + self._implicit_app_ctx_stack.append(app_ctx) + else: + self._implicit_app_ctx_stack.append(None) + + if hasattr(sys, 'exc_clear'): + sys.exc_clear() + + _request_ctx_stack.push(self) + + # Open the session at the moment that the request context is + # available. This allows a custom open_session method to use the + # request context (e.g. code that access database information + # stored on `g` instead of the appcontext). + self.session = self.app.open_session(self.request) + if self.session is None: + self.session = self.app.make_null_session() + + def pop(self, exc=_sentinel): + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + app_ctx = self._implicit_app_ctx_stack.pop() + + try: + clear_request = False + if not self._implicit_app_ctx_stack: + self.preserved = False + self._preserved_exc = None + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + # If this interpreter supports clearing the exception information + # we do that now. This will only go into effect on Python 2.x, + # on 3.x it disappears automatically at the end of the exception + # stack. + if hasattr(sys, 'exc_clear'): + sys.exc_clear() + + request_close = getattr(self.request, 'close', None) + if request_close is not None: + request_close() + clear_request = True + finally: + rv = _request_ctx_stack.pop() + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + rv.request.environ['werkzeug.request'] = None + + # Get rid of the app as well if necessary. + if app_ctx is not None: + app_ctx.pop(exc) + + assert rv is self, 'Popped wrong request context. ' \ + '(%r instead of %r)' % (rv, self) + + def auto_pop(self, exc): + if self.request.environ.get('flask._preserve_context') or \ + (exc is not None and self.app.preserve_context_on_exception): + self.preserved = True + self._preserved_exc = exc + else: + self.pop(exc) + + def __enter__(self): + self.push() + return self + + def __exit__(self, exc_type, exc_value, tb): + # do not pop the request stack if we are in debug mode and an + # exception happened. This will allow the debugger to still + # access the request object in the interactive shell. Furthermore + # the context can be force kept alive for the test client. + # See flask.testing for how this works. + self.auto_pop(exc_value) + + if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: + reraise(exc_type, exc_value, tb) + + def __repr__(self): + return '<%s \'%s\' [%s] of %s>' % ( + self.__class__.__name__, + self.request.url, + self.request.method, + self.app.name, + ) diff --git a/venv/lib/python2.7/site-packages/flask/ctx.pyc b/venv/lib/python2.7/site-packages/flask/ctx.pyc new file mode 100644 index 0000000..ebd28cb Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/ctx.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/debughelpers.py b/venv/lib/python2.7/site-packages/flask/debughelpers.py new file mode 100644 index 0000000..90710dd --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/debughelpers.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +""" + flask.debughelpers + ~~~~~~~~~~~~~~~~~~ + + Various helpers to make the development experience better. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +from ._compat import implements_to_string, text_type +from .app import Flask +from .blueprints import Blueprint +from .globals import _request_ctx_stack + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +@implements_to_string +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request, key): + form_matches = request.form.getlist(key) + buf = ['You tried to access the file "%s" in the request.files ' + 'dictionary but it does not exist. The mimetype for the request ' + 'is "%s" instead of "multipart/form-data" which means that no ' + 'file contents were transmitted. To fix this error you should ' + 'provide enctype="multipart/form-data" in your form.' % + (key, request.mimetype)] + if form_matches: + buf.append('\n\nThe browser instead transmitted some file names. ' + 'This was submitted: %s' % ', '.join('"%s"' % x + for x in form_matches)) + self.msg = ''.join(buf) + + def __str__(self): + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised by Flask in debug mode if it detects a + redirect caused by the routing system when the request method is not + GET, HEAD or OPTIONS. Reasoning: form data will be dropped. + """ + + def __init__(self, request): + exc = request.routing_exception + buf = ['A request was sent to this URL (%s) but a redirect was ' + 'issued automatically by the routing system to "%s".' + % (request.url, exc.new_url)] + + # In case just a slash was appended we can be extra helpful + if request.base_url + '/' == exc.new_url.split('?')[0]: + buf.append(' The URL was defined with a trailing slash so ' + 'Flask will automatically redirect to the URL ' + 'with the trailing slash if it was accessed ' + 'without one.') + + buf.append(' Make sure to directly send your %s-request to this URL ' + 'since we can\'t make browsers or HTTP clients redirect ' + 'with form data reliably or without user interaction.' % + request.method) + buf.append('\n\nNote: this exception is only raised in debug mode') + AssertionError.__init__(self, ''.join(buf).encode('utf-8')) + + +def attach_enctype_error_multidict(request): + """Since Flask 0.8 we're monkeypatching the files object in case a + request is detected that does not use multipart form data but the files + object is accessed. + """ + oldcls = request.files.__class__ + class newcls(oldcls): + def __getitem__(self, key): + try: + return oldcls.__getitem__(self, key) + except KeyError: + if key not in request.form: + raise + raise DebugFilesKeyError(request, key) + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader): + yield 'class: %s.%s' % (type(loader).__module__, type(loader).__name__) + for key, value in sorted(loader.__dict__.items()): + if key.startswith('_'): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, (str, text_type)) for x in value): + continue + yield '%s:' % key + for item in value: + yield ' - %s' % item + continue + elif not isinstance(value, (str, text_type, int, float, bool)): + continue + yield '%s: %r' % (key, value) + + +def explain_template_loading_attempts(app, template, attempts): + """This should help developers understand what failed""" + info = ['Locating template "%s":' % template] + total_found = 0 + blueprint = None + reqctx = _request_ctx_stack.top + if reqctx is not None and reqctx.request.blueprint is not None: + blueprint = reqctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, Flask): + src_info = 'application "%s"' % srcobj.import_name + elif isinstance(srcobj, Blueprint): + src_info = 'blueprint "%s" (%s)' % (srcobj.name, + srcobj.import_name) + else: + src_info = repr(srcobj) + + info.append('% 5d: trying loader of %s' % ( + idx + 1, src_info)) + + for line in _dump_loader_info(loader): + info.append(' %s' % line) + + if triple is None: + detail = 'no match' + else: + detail = 'found (%r)' % (triple[1] or '') + total_found += 1 + info.append(' -> %s' % detail) + + seems_fishy = False + if total_found == 0: + info.append('Error: the template could not be found.') + seems_fishy = True + elif total_found > 1: + info.append('Warning: multiple loaders returned a match for the template.') + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append(' The template was looked up from an endpoint that ' + 'belongs to the blueprint "%s".' % blueprint) + info.append(' Maybe you did not place a template in the right folder?') + info.append(' See http://flask.pocoo.org/docs/blueprints/#templates') + + app.logger.info('\n'.join(info)) diff --git a/venv/lib/python2.7/site-packages/flask/debughelpers.pyc b/venv/lib/python2.7/site-packages/flask/debughelpers.pyc new file mode 100644 index 0000000..8364262 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/debughelpers.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/ext/__init__.py b/venv/lib/python2.7/site-packages/flask/ext/__init__.py new file mode 100644 index 0000000..051f44a --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/ext/__init__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" + flask.ext + ~~~~~~~~~ + + Redirect imports for extensions. This module basically makes it possible + for us to transition from flaskext.foo to flask_foo without having to + force all extensions to upgrade at the same time. + + When a user does ``from flask.ext.foo import bar`` it will attempt to + import ``from flask_foo import bar`` first and when that fails it will + try to import ``from flaskext.foo import bar``. + + We're switching from namespace packages because it was just too painful for + everybody involved. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + + +def setup(): + from ..exthook import ExtensionImporter + importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], __name__) + importer.install() + + +setup() +del setup diff --git a/venv/lib/python2.7/site-packages/flask/ext/__init__.pyc b/venv/lib/python2.7/site-packages/flask/ext/__init__.pyc new file mode 100644 index 0000000..d3311d3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/ext/__init__.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/exthook.py b/venv/lib/python2.7/site-packages/flask/exthook.py new file mode 100644 index 0000000..d884280 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/exthook.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +""" + flask.exthook + ~~~~~~~~~~~~~ + + Redirect imports for extensions. This module basically makes it possible + for us to transition from flaskext.foo to flask_foo without having to + force all extensions to upgrade at the same time. + + When a user does ``from flask.ext.foo import bar`` it will attempt to + import ``from flask_foo import bar`` first and when that fails it will + try to import ``from flaskext.foo import bar``. + + We're switching from namespace packages because it was just too painful for + everybody involved. + + This is used by `flask.ext`. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import sys +import os +import warnings +from ._compat import reraise + + +class ExtDeprecationWarning(DeprecationWarning): + pass + +warnings.simplefilter('always', ExtDeprecationWarning) + + +class ExtensionImporter(object): + """This importer redirects imports from this submodule to other locations. + This makes it possible to transition from the old flaskext.name to the + newer flask_name without people having a hard time. + """ + + def __init__(self, module_choices, wrapper_module): + self.module_choices = module_choices + self.wrapper_module = wrapper_module + self.prefix = wrapper_module + '.' + self.prefix_cutoff = wrapper_module.count('.') + 1 + + def __eq__(self, other): + return self.__class__.__module__ == other.__class__.__module__ and \ + self.__class__.__name__ == other.__class__.__name__ and \ + self.wrapper_module == other.wrapper_module and \ + self.module_choices == other.module_choices + + def __ne__(self, other): + return not self.__eq__(other) + + def install(self): + sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self] + + def find_module(self, fullname, path=None): + if fullname.startswith(self.prefix) and \ + fullname != 'flask.ext.ExtDeprecationWarning': + return self + + def load_module(self, fullname): + if fullname in sys.modules: + return sys.modules[fullname] + + modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff] + + warnings.warn( + "Importing flask.ext.{x} is deprecated, use flask_{x} instead." + .format(x=modname), ExtDeprecationWarning, stacklevel=2 + ) + + for path in self.module_choices: + realname = path % modname + try: + __import__(realname) + except ImportError: + exc_type, exc_value, tb = sys.exc_info() + # since we only establish the entry in sys.modules at the + # very this seems to be redundant, but if recursive imports + # happen we will call into the move import a second time. + # On the second invocation we still don't have an entry for + # fullname in sys.modules, but we will end up with the same + # fake module name and that import will succeed since this + # one already has a temporary entry in the modules dict. + # Since this one "succeeded" temporarily that second + # invocation now will have created a fullname entry in + # sys.modules which we have to kill. + sys.modules.pop(fullname, None) + + # If it's an important traceback we reraise it, otherwise + # we swallow it and try the next choice. The skipped frame + # is the one from __import__ above which we don't care about + if self.is_important_traceback(realname, tb): + reraise(exc_type, exc_value, tb.tb_next) + continue + module = sys.modules[fullname] = sys.modules[realname] + if '.' not in modname: + setattr(sys.modules[self.wrapper_module], modname, module) + + if realname.startswith('flaskext.'): + warnings.warn( + "Detected extension named flaskext.{x}, please rename it " + "to flask_{x}. The old form is deprecated." + .format(x=modname), ExtDeprecationWarning + ) + + return module + raise ImportError('No module named %s' % fullname) + + def is_important_traceback(self, important_module, tb): + """Walks a traceback's frames and checks if any of the frames + originated in the given important module. If that is the case then we + were able to import the module itself but apparently something went + wrong when the module was imported. (Eg: import of an import failed). + """ + while tb is not None: + if self.is_important_frame(important_module, tb): + return True + tb = tb.tb_next + return False + + def is_important_frame(self, important_module, tb): + """Checks a single frame if it's important.""" + g = tb.tb_frame.f_globals + if '__name__' not in g: + return False + + module_name = g['__name__'] + + # Python 2.7 Behavior. Modules are cleaned up late so the + # name shows up properly here. Success! + if module_name == important_module: + return True + + # Some python versions will clean up modules so early that the + # module name at that point is no longer set. Try guessing from + # the filename then. + filename = os.path.abspath(tb.tb_frame.f_code.co_filename) + test_string = os.path.sep + important_module.replace('.', os.path.sep) + return test_string + '.py' in filename or \ + test_string + os.path.sep + '__init__.py' in filename diff --git a/venv/lib/python2.7/site-packages/flask/exthook.pyc b/venv/lib/python2.7/site-packages/flask/exthook.pyc new file mode 100644 index 0000000..03f8e78 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/exthook.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/globals.py b/venv/lib/python2.7/site-packages/flask/globals.py new file mode 100644 index 0000000..0b70a3e --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/globals.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +""" + flask.globals + ~~~~~~~~~~~~~ + + Defines all the global objects that are proxies to the current + active context. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +from functools import partial +from werkzeug.local import LocalStack, LocalProxy + + +_request_ctx_err_msg = '''\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +''' +_app_ctx_err_msg = '''\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +to interface with the current application object in a way. To solve +this set up an application context with app.app_context(). See the +documentation for more information.\ +''' + + +def _lookup_req_object(name): + top = _request_ctx_stack.top + if top is None: + raise RuntimeError(_request_ctx_err_msg) + return getattr(top, name) + + +def _lookup_app_object(name): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError(_app_ctx_err_msg) + return getattr(top, name) + + +def _find_app(): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError(_app_ctx_err_msg) + return top.app + + +# context locals +_request_ctx_stack = LocalStack() +_app_ctx_stack = LocalStack() +current_app = LocalProxy(_find_app) +request = LocalProxy(partial(_lookup_req_object, 'request')) +session = LocalProxy(partial(_lookup_req_object, 'session')) +g = LocalProxy(partial(_lookup_app_object, 'g')) diff --git a/venv/lib/python2.7/site-packages/flask/globals.pyc b/venv/lib/python2.7/site-packages/flask/globals.pyc new file mode 100644 index 0000000..ec3fcc0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/globals.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/helpers.py b/venv/lib/python2.7/site-packages/flask/helpers.py new file mode 100644 index 0000000..c6c2cdd --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/helpers.py @@ -0,0 +1,960 @@ +# -*- coding: utf-8 -*- +""" + flask.helpers + ~~~~~~~~~~~~~ + + Implements various helpers. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +import os +import sys +import pkgutil +import posixpath +import mimetypes +from time import time +from zlib import adler32 +from threading import RLock +from werkzeug.routing import BuildError +from functools import update_wrapper + +try: + from werkzeug.urls import url_quote +except ImportError: + from urlparse import quote as url_quote + +from werkzeug.datastructures import Headers, Range +from werkzeug.exceptions import BadRequest, NotFound, \ + RequestedRangeNotSatisfiable + +# this was moved in 0.7 +try: + from werkzeug.wsgi import wrap_file +except ImportError: + from werkzeug.utils import wrap_file + +from jinja2 import FileSystemLoader + +from .signals import message_flashed +from .globals import session, _request_ctx_stack, _app_ctx_stack, \ + current_app, request +from ._compat import string_types, text_type + + +# sentinel +_missing = object() + + +# what separators does this operating system provide that are not a slash? +# this is used by the send_from_directory function to ensure that nobody is +# able to access files from outside the filesystem. +_os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep] + if sep not in (None, '/')) + + +def get_debug_flag(default=None): + val = os.environ.get('FLASK_DEBUG') + if not val: + return default + return val not in ('0', 'false', 'no') + + +def _endpoint_from_view_func(view_func): + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, 'expected view func if endpoint ' \ + 'is not provided.' + return view_func.__name__ + + +def stream_with_context(generator_or_function): + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) + except TypeError: + def decorator(*args, **kwargs): + gen = generator_or_function(*args, **kwargs) + return stream_with_context(gen) + return update_wrapper(decorator, generator_or_function) + + def generator(): + ctx = _request_ctx_stack.top + if ctx is None: + raise RuntimeError('Attempted to stream with context but ' + 'there was no context in the first place to keep around.') + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + for item in gen: + yield item + finally: + if hasattr(gen, 'close'): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g + + +def make_response(*args): + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + +def url_for(endpoint, **values): + """Generates a URL to the given endpoint with the method provided. + + Variable arguments that are unknown to the target endpoint are appended + to the generated URL as query arguments. If the value of a query argument + is ``None``, the whole pair is skipped. In case blueprints are active + you can shortcut references to the same blueprint by prefixing the + local endpoint with a dot (``.``). + + This will reference the index function local to the current blueprint:: + + url_for('.index') + + For more information, head over to the :ref:`Quickstart `. + + To integrate applications, :class:`Flask` has a hook to intercept URL build + errors through :attr:`Flask.url_build_error_handlers`. The `url_for` + function results in a :exc:`~werkzeug.routing.BuildError` when the current + app does not have a URL for the given endpoint and values. When it does, the + :data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if + it is not ``None``, which can return a string to use as the result of + `url_for` (instead of `url_for`'s default to raise the + :exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception. + An example:: + + def external_url_handler(error, endpoint, values): + "Looks up an external URL when `url_for` cannot build a URL." + # This is an example of hooking the build_error_handler. + # Here, lookup_url is some utility function you've built + # which looks up the endpoint in some external URL registry. + url = lookup_url(endpoint, **values) + if url is None: + # External lookup did not have a URL. + # Re-raise the BuildError, in context of original traceback. + exc_type, exc_value, tb = sys.exc_info() + if exc_value is error: + raise exc_type, exc_value, tb + else: + raise error + # url_for will use this result, instead of raising BuildError. + return url + + app.url_build_error_handlers.append(external_url_handler) + + Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and + `endpoint` and `values` are the arguments passed into `url_for`. Note + that this is for building URLs outside the current application, and not for + handling 404 NotFound errors. + + .. versionadded:: 0.10 + The `_scheme` parameter was added. + + .. versionadded:: 0.9 + The `_anchor` and `_method` parameters were added. + + .. versionadded:: 0.9 + Calls :meth:`Flask.handle_build_error` on + :exc:`~werkzeug.routing.BuildError`. + + :param endpoint: the endpoint of the URL (name of the function) + :param values: the variable arguments of the URL rule + :param _external: if set to ``True``, an absolute URL is generated. Server + address can be changed via ``SERVER_NAME`` configuration variable which + defaults to `localhost`. + :param _scheme: a string specifying the desired URL scheme. The `_external` + parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default + behavior uses the same scheme as the current request, or + ``PREFERRED_URL_SCHEME`` from the :ref:`app configuration ` if no + request context is available. As of Werkzeug 0.10, this also can be set + to an empty string to build protocol-relative URLs. + :param _anchor: if provided this is added as anchor to the URL. + :param _method: if provided this explicitly specifies an HTTP method. + """ + appctx = _app_ctx_stack.top + reqctx = _request_ctx_stack.top + if appctx is None: + raise RuntimeError('Attempted to generate a URL without the ' + 'application context being pushed. This has to be ' + 'executed when application context is available.') + + # If request specific information is available we have some extra + # features that support "relative" URLs. + if reqctx is not None: + url_adapter = reqctx.url_adapter + blueprint_name = request.blueprint + if not reqctx.request._is_old_module: + if endpoint[:1] == '.': + if blueprint_name is not None: + endpoint = blueprint_name + endpoint + else: + endpoint = endpoint[1:] + else: + # TODO: get rid of this deprecated functionality in 1.0 + if '.' not in endpoint: + if blueprint_name is not None: + endpoint = blueprint_name + '.' + endpoint + elif endpoint.startswith('.'): + endpoint = endpoint[1:] + external = values.pop('_external', False) + + # Otherwise go with the url adapter from the appctx and make + # the URLs external by default. + else: + url_adapter = appctx.url_adapter + if url_adapter is None: + raise RuntimeError('Application was not able to create a URL ' + 'adapter for request independent URL generation. ' + 'You might be able to fix this by setting ' + 'the SERVER_NAME config variable.') + external = values.pop('_external', True) + + anchor = values.pop('_anchor', None) + method = values.pop('_method', None) + scheme = values.pop('_scheme', None) + appctx.app.inject_url_defaults(endpoint, values) + + # This is not the best way to deal with this but currently the + # underlying Werkzeug router does not support overriding the scheme on + # a per build call basis. + old_scheme = None + if scheme is not None: + if not external: + raise ValueError('When specifying _scheme, _external must be True') + old_scheme = url_adapter.url_scheme + url_adapter.url_scheme = scheme + + try: + try: + rv = url_adapter.build(endpoint, values, method=method, + force_external=external) + finally: + if old_scheme is not None: + url_adapter.url_scheme = old_scheme + except BuildError as error: + # We need to inject the values again so that the app callback can + # deal with that sort of stuff. + values['_external'] = external + values['_anchor'] = anchor + values['_method'] = method + return appctx.app.handle_url_build_error(error, endpoint, values) + + if anchor is not None: + rv += '#' + url_quote(anchor) + return rv + + +def get_template_attribute(template_name, attribute): + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, + attribute) + + +def flash(message, category='message'): + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # are always in sync with the session object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get('_flashes', []) + flashes.append((category, message)) + session['_flashes'] = flashes + message_flashed.send(current_app._get_current_object(), + message=message, category=category) + + +def get_flashed_messages(with_categories=False, category_filter=[]): + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to ``True``, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (``True`` gives a tuple, where ``False`` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :ref:`message-flashing-pattern` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to ``True`` to also receive categories. + :param category_filter: whitelist of categories to limit return values + """ + flashes = _request_ctx_stack.top.flashes + if flashes is None: + _request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \ + if '_flashes' in session else [] + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def send_file(filename_or_fp, mimetype=None, as_attachment=False, + attachment_filename=None, add_etags=True, + cache_timeout=None, conditional=False, last_modified=None): + """Sends the contents of a file to the client. This will use the + most efficient method available and configured. By default it will + try to use the WSGI server's file_wrapper support. Alternatively + you can set the application's :attr:`~Flask.use_x_sendfile` attribute + to ``True`` to directly emit an ``X-Sendfile`` header. This however + requires support of the underlying webserver for ``X-Sendfile``. + + By default it will try to guess the mimetype for you, but you can + also explicitly provide one. For extra security you probably want + to send certain files as attachment (HTML for instance). The mimetype + guessing requires a `filename` or an `attachment_filename` to be + provided. + + ETags will also be attached automatically if a `filename` is provided. You + can turn this off by setting `add_etags=False`. + + If `conditional=True` and `filename` is provided, this method will try to + upgrade the response stream to support range requests. This will allow + the request to be answered with partial content response. + + Please never pass filenames to this function from user sources; + you should use :func:`send_from_directory` instead. + + .. versionadded:: 0.2 + + .. versionadded:: 0.5 + The `add_etags`, `cache_timeout` and `conditional` parameters were + added. The default behavior is now to attach etags. + + .. versionchanged:: 0.7 + mimetype guessing and etag support for file objects was + deprecated because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. This functionality + will be removed in Flask 1.0 + + .. versionchanged:: 0.9 + cache_timeout pulls its default from application config, when None. + + .. versionchanged:: 0.12 + The filename is no longer automatically inferred from file objects. If + you want to use automatic mimetype and etag support, pass a filepath via + `filename_or_fp` or `attachment_filename`. + + .. versionchanged:: 0.12 + The `attachment_filename` is preferred over `filename` for MIME-type + detection. + + :param filename_or_fp: the filename of the file to send in `latin-1`. + This is relative to the :attr:`~Flask.root_path` + if a relative path is specified. + Alternatively a file object might be provided in + which case ``X-Sendfile`` might not work and fall + back to the traditional method. Make sure that the + file pointer is positioned at the start of data to + send before calling :func:`send_file`. + :param mimetype: the mimetype of the file if provided. If a file path is + given, auto detection happens as fallback, otherwise an + error will be raised. + :param as_attachment: set to ``True`` if you want to send this file with + a ``Content-Disposition: attachment`` header. + :param attachment_filename: the filename for the attachment if it + differs from the file's filename. + :param add_etags: set to ``False`` to disable attaching of etags. + :param conditional: set to ``True`` to enable conditional responses. + + :param cache_timeout: the timeout in seconds for the headers. When ``None`` + (default), this value is set by + :meth:`~Flask.get_send_file_max_age` of + :data:`~flask.current_app`. + :param last_modified: set the ``Last-Modified`` header to this value, + a :class:`~datetime.datetime` or timestamp. + If a file was passed, this overrides its mtime. + """ + mtime = None + fsize = None + if isinstance(filename_or_fp, string_types): + filename = filename_or_fp + if not os.path.isabs(filename): + filename = os.path.join(current_app.root_path, filename) + file = None + if attachment_filename is None: + attachment_filename = os.path.basename(filename) + else: + file = filename_or_fp + filename = None + + if mimetype is None: + if attachment_filename is not None: + mimetype = mimetypes.guess_type(attachment_filename)[0] \ + or 'application/octet-stream' + + if mimetype is None: + raise ValueError( + 'Unable to infer MIME-type because no filename is available. ' + 'Please set either `attachment_filename`, pass a filepath to ' + '`filename_or_fp` or set your own MIME-type via `mimetype`.' + ) + + headers = Headers() + if as_attachment: + if attachment_filename is None: + raise TypeError('filename unavailable, required for ' + 'sending as attachment') + headers.add('Content-Disposition', 'attachment', + filename=attachment_filename) + + if current_app.use_x_sendfile and filename: + if file is not None: + file.close() + headers['X-Sendfile'] = filename + fsize = os.path.getsize(filename) + headers['Content-Length'] = fsize + data = None + else: + if file is None: + file = open(filename, 'rb') + mtime = os.path.getmtime(filename) + fsize = os.path.getsize(filename) + headers['Content-Length'] = fsize + data = wrap_file(request.environ, file) + + rv = current_app.response_class(data, mimetype=mimetype, headers=headers, + direct_passthrough=True) + + if last_modified is not None: + rv.last_modified = last_modified + elif mtime is not None: + rv.last_modified = mtime + + rv.cache_control.public = True + if cache_timeout is None: + cache_timeout = current_app.get_send_file_max_age(filename) + if cache_timeout is not None: + rv.cache_control.max_age = cache_timeout + rv.expires = int(time() + cache_timeout) + + if add_etags and filename is not None: + from warnings import warn + + try: + rv.set_etag('%s-%s-%s' % ( + os.path.getmtime(filename), + os.path.getsize(filename), + adler32( + filename.encode('utf-8') if isinstance(filename, text_type) + else filename + ) & 0xffffffff + )) + except OSError: + warn('Access %s failed, maybe it does not exist, so ignore etags in ' + 'headers' % filename, stacklevel=2) + + if conditional: + if callable(getattr(Range, 'to_content_range_header', None)): + # Werkzeug supports Range Requests + # Remove this test when support for Werkzeug <0.12 is dropped + try: + rv = rv.make_conditional(request, accept_ranges=True, + complete_length=fsize) + except RequestedRangeNotSatisfiable: + file.close() + raise + else: + rv = rv.make_conditional(request) + # make sure we don't send x-sendfile for servers that + # ignore the 304 status code for x-sendfile. + if rv.status_code == 304: + rv.headers.pop('x-sendfile', None) + return rv + + +def safe_join(directory, *pathnames): + """Safely join `directory` and zero or more untrusted `pathnames` + components. + + Example usage:: + + @app.route('/wiki/') + def wiki_page(filename): + filename = safe_join(app.config['WIKI_FOLDER'], filename) + with open(filename, 'rb') as fd: + content = fd.read() # Read and process the file content... + + :param directory: the trusted base directory. + :param pathnames: the untrusted pathnames relative to that directory. + :raises: :class:`~werkzeug.exceptions.NotFound` if one or more passed + paths fall out of its boundaries. + """ + for filename in pathnames: + if filename != '': + filename = posixpath.normpath(filename) + for sep in _os_alt_seps: + if sep in filename: + raise NotFound() + if os.path.isabs(filename) or \ + filename == '..' or \ + filename.startswith('../'): + raise NotFound() + directory = os.path.join(directory, filename) + return directory + + +def send_from_directory(directory, filename, **options): + """Send a file from a given directory with :func:`send_file`. This + is a secure way to quickly expose static files from an upload folder + or something similar. + + Example usage:: + + @app.route('/uploads/') + def download_file(filename): + return send_from_directory(app.config['UPLOAD_FOLDER'], + filename, as_attachment=True) + + .. admonition:: Sending files and Performance + + It is strongly recommended to activate either ``X-Sendfile`` support in + your webserver or (if no authentication happens) to tell the webserver + to serve files for the given path on its own without calling into the + web application for improved performance. + + .. versionadded:: 0.5 + + :param directory: the directory where all the files are stored. + :param filename: the filename relative to that directory to + download. + :param options: optional keyword arguments that are directly + forwarded to :func:`send_file`. + """ + filename = safe_join(directory, filename) + if not os.path.isabs(filename): + filename = os.path.join(current_app.root_path, filename) + try: + if not os.path.isfile(filename): + raise NotFound() + except (TypeError, ValueError): + raise BadRequest() + options.setdefault('conditional', True) + return send_file(filename, **options) + + +def get_root_path(import_name): + """Returns the path to a package or cwd if that cannot be found. This + returns the path of a package or the folder that contains a module. + + Not to be confused with the package path returned by :func:`find_package`. + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + if mod is not None and hasattr(mod, '__file__'): + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + loader = pkgutil.get_loader(import_name) + + # Loader does not exist or we're referring to an unloaded main module + # or a main module without path (interactive sessions), go with the + # current working directory. + if loader is None or import_name == '__main__': + return os.getcwd() + + # For .egg, zipimporter does not have get_filename until Python 2.7. + # Some other loaders might exhibit the same behavior. + if hasattr(loader, 'get_filename'): + filepath = loader.get_filename(import_name) + else: + # Fall back to imports. + __import__(import_name) + mod = sys.modules[import_name] + filepath = getattr(mod, '__file__', None) + + # If we don't have a filepath it might be because we are a + # namespace package. In this case we pick the root path from the + # first module that is contained in our package. + if filepath is None: + raise RuntimeError('No root path can be found for the provided ' + 'module "%s". This can happen because the ' + 'module came from an import hook that does ' + 'not provide file name information or because ' + 'it\'s a namespace package. In this case ' + 'the root path needs to be explicitly ' + 'provided.' % import_name) + + # filepath is import_name.py for a module, or __init__.py for a package. + return os.path.dirname(os.path.abspath(filepath)) + + +def _matching_loader_thinks_module_is_package(loader, mod_name): + """Given the loader that loaded a module and the module this function + attempts to figure out if the given module is actually a package. + """ + # If the loader can tell us if something is a package, we can + # directly ask the loader. + if hasattr(loader, 'is_package'): + return loader.is_package(mod_name) + # importlib's namespace loaders do not have this functionality but + # all the modules it loads are packages, so we can take advantage of + # this information. + elif (loader.__class__.__module__ == '_frozen_importlib' and + loader.__class__.__name__ == 'NamespaceLoader'): + return True + # Otherwise we need to fail with an error that explains what went + # wrong. + raise AttributeError( + ('%s.is_package() method is missing but is required by Flask of ' + 'PEP 302 import hooks. If you do not use import hooks and ' + 'you encounter this error please file a bug against Flask.') % + loader.__class__.__name__) + + +def find_package(import_name): + """Finds a package and returns the prefix (or None if the package is + not installed) as well as the folder that contains the package or + module as a tuple. The package path returned is the module that would + have to be added to the pythonpath in order to make it possible to + import the module. The prefix is the path below which a UNIX like + folder structure exists (lib, share etc.). + """ + root_mod_name = import_name.split('.')[0] + loader = pkgutil.get_loader(root_mod_name) + if loader is None or import_name == '__main__': + # import name is not found, or interactive/main module + package_path = os.getcwd() + else: + # For .egg, zipimporter does not have get_filename until Python 2.7. + if hasattr(loader, 'get_filename'): + filename = loader.get_filename(root_mod_name) + elif hasattr(loader, 'archive'): + # zipimporter's loader.archive points to the .egg or .zip + # archive filename is dropped in call to dirname below. + filename = loader.archive + else: + # At least one loader is missing both get_filename and archive: + # Google App Engine's HardenedModulesHook + # + # Fall back to imports. + __import__(import_name) + filename = sys.modules[import_name].__file__ + package_path = os.path.abspath(os.path.dirname(filename)) + + # In case the root module is a package we need to chop of the + # rightmost part. This needs to go through a helper function + # because of python 3.3 namespace packages. + if _matching_loader_thinks_module_is_package( + loader, root_mod_name): + package_path = os.path.dirname(package_path) + + site_parent, site_folder = os.path.split(package_path) + py_prefix = os.path.abspath(sys.prefix) + if package_path.startswith(py_prefix): + return py_prefix, package_path + elif site_folder.lower() == 'site-packages': + parent, folder = os.path.split(site_parent) + # Windows like installations + if folder.lower() == 'lib': + base_dir = parent + # UNIX like installations + elif os.path.basename(parent).lower() == 'lib': + base_dir = os.path.dirname(parent) + else: + base_dir = site_parent + return base_dir, package_path + return None, package_path + + +class locked_cached_property(object): + """A decorator that converts a function into a lazy property. The + function wrapped is called the first time to retrieve the result + and then that calculated result is used the next time you access + the value. Works like the one in Werkzeug but has a lock for + thread safety. + """ + + def __init__(self, func, name=None, doc=None): + self.__name__ = name or func.__name__ + self.__module__ = func.__module__ + self.__doc__ = doc or func.__doc__ + self.func = func + self.lock = RLock() + + def __get__(self, obj, type=None): + if obj is None: + return self + with self.lock: + value = obj.__dict__.get(self.__name__, _missing) + if value is _missing: + value = self.func(obj) + obj.__dict__[self.__name__] = value + return value + + +class _PackageBoundObject(object): + + def __init__(self, import_name, template_folder=None, root_path=None): + #: The name of the package or module. Do not change this once + #: it was set by the constructor. + self.import_name = import_name + + #: location of the templates. ``None`` if templates should not be + #: exposed. + self.template_folder = template_folder + + if root_path is None: + root_path = get_root_path(self.import_name) + + #: Where is the app root located? + self.root_path = root_path + + self._static_folder = None + self._static_url_path = None + + def _get_static_folder(self): + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + def _set_static_folder(self, value): + self._static_folder = value + static_folder = property(_get_static_folder, _set_static_folder, doc=''' + The absolute path to the configured static folder. + ''') + del _get_static_folder, _set_static_folder + + def _get_static_url_path(self): + if self._static_url_path is not None: + return self._static_url_path + if self.static_folder is not None: + return '/' + os.path.basename(self.static_folder) + def _set_static_url_path(self, value): + self._static_url_path = value + static_url_path = property(_get_static_url_path, _set_static_url_path) + del _get_static_url_path, _set_static_url_path + + @property + def has_static_folder(self): + """This is ``True`` if the package bound object's container has a + folder for static files. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @locked_cached_property + def jinja_loader(self): + """The Jinja loader for this package bound object. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, + self.template_folder)) + + def get_send_file_max_age(self, filename): + """Provides default cache_timeout for the :func:`send_file` functions. + + By default, this function returns ``SEND_FILE_MAX_AGE_DEFAULT`` from + the configuration of :data:`~flask.current_app`. + + Static file functions such as :func:`send_from_directory` use this + function, and :func:`send_file` calls this function on + :data:`~flask.current_app` when the given cache_timeout is ``None``. If a + cache_timeout is given in :func:`send_file`, that timeout is used; + otherwise, this method is called. + + This allows subclasses to change the behavior when sending files based + on the filename. For example, to set the cache timeout for .js files + to 60 seconds:: + + class MyFlask(flask.Flask): + def get_send_file_max_age(self, name): + if name.lower().endswith('.js'): + return 60 + return flask.Flask.get_send_file_max_age(self, name) + + .. versionadded:: 0.9 + """ + return total_seconds(current_app.send_file_max_age_default) + + def send_static_file(self, filename): + """Function used internally to send static files from the static + folder to the browser. + + .. versionadded:: 0.5 + """ + if not self.has_static_folder: + raise RuntimeError('No static folder for this object') + # Ensure get_send_file_max_age is called in all cases. + # Here, we ensure get_send_file_max_age is called for Blueprints. + cache_timeout = self.get_send_file_max_age(filename) + return send_from_directory(self.static_folder, filename, + cache_timeout=cache_timeout) + + def open_resource(self, resource, mode='rb'): + """Opens a resource from the application's resource folder. To see + how this works, consider the following folder structure:: + + /myapplication.py + /schema.sql + /static + /style.css + /templates + /layout.html + /index.html + + If you want to open the :file:`schema.sql` file you would do the + following:: + + with app.open_resource('schema.sql') as f: + contents = f.read() + do_something_with(contents) + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + if mode not in ('r', 'rb'): + raise ValueError('Resources can only be opened for reading') + return open(os.path.join(self.root_path, resource), mode) + + +def total_seconds(td): + """Returns the total seconds from a timedelta object. + + :param timedelta td: the timedelta to be converted in seconds + + :returns: number of seconds + :rtype: int + """ + return td.days * 60 * 60 * 24 + td.seconds diff --git a/venv/lib/python2.7/site-packages/flask/helpers.pyc b/venv/lib/python2.7/site-packages/flask/helpers.pyc new file mode 100644 index 0000000..aa703f6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/flask/helpers.pyc differ diff --git a/venv/lib/python2.7/site-packages/flask/json.py b/venv/lib/python2.7/site-packages/flask/json.py new file mode 100644 index 0000000..16e0c29 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/json.py @@ -0,0 +1,269 @@ +# -*- coding: utf-8 -*- +""" + flask.jsonimpl + ~~~~~~~~~~~~~~ + + Implementation helpers for the JSON support in Flask. + + :copyright: (c) 2015 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import io +import uuid +from datetime import date +from .globals import current_app, request +from ._compat import text_type, PY2 + +from werkzeug.http import http_date +from jinja2 import Markup + +# Use the same json implementation as itsdangerous on which we +# depend anyways. +from itsdangerous import json as _json + + +# Figure out if simplejson escapes slashes. This behavior was changed +# from one version to another without reason. +_slash_escape = '\\/' not in _json.dumps('/') + + +__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump', + 'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder', + 'jsonify'] + + +def _wrap_reader_for_text(fp, encoding): + if isinstance(fp.read(0), bytes): + fp = io.TextIOWrapper(io.BufferedReader(fp), encoding) + return fp + + +def _wrap_writer_for_text(fp, encoding): + try: + fp.write('') + except TypeError: + fp = io.TextIOWrapper(fp, encoding) + return fp + + +class JSONEncoder(_json.JSONEncoder): + """The default Flask JSON encoder. This one extends the default simplejson + encoder by also supporting ``datetime`` objects, ``UUID`` as well as + ``Markup`` objects which are serialized as RFC 822 datetime strings (same + as the HTTP date format). In order to support more data types override the + :meth:`default` method. + """ + + def default(self, o): + """Implement this method in a subclass such that it returns a + serializable object for ``o``, or calls the base implementation (to + raise a :exc:`TypeError`). + + For example, to support arbitrary iterators, you could implement + default like this:: + + def default(self, o): + try: + iterable = iter(o) + except TypeError: + pass + else: + return list(iterable) + return JSONEncoder.default(self, o) + """ + if isinstance(o, date): + return http_date(o.timetuple()) + if isinstance(o, uuid.UUID): + return str(o) + if hasattr(o, '__html__'): + return text_type(o.__html__()) + return _json.JSONEncoder.default(self, o) + + +class JSONDecoder(_json.JSONDecoder): + """The default JSON decoder. This one does not change the behavior from + the default simplejson decoder. Consult the :mod:`json` documentation + for more information. This decoder is not only used for the load + functions of this module but also :attr:`~flask.Request`. + """ + + +def _dump_arg_defaults(kwargs): + """Inject default arguments for dump functions.""" + if current_app: + kwargs.setdefault('cls', current_app.json_encoder) + if not current_app.config['JSON_AS_ASCII']: + kwargs.setdefault('ensure_ascii', False) + kwargs.setdefault('sort_keys', current_app.config['JSON_SORT_KEYS']) + else: + kwargs.setdefault('sort_keys', True) + kwargs.setdefault('cls', JSONEncoder) + + +def _load_arg_defaults(kwargs): + """Inject default arguments for load functions.""" + if current_app: + kwargs.setdefault('cls', current_app.json_decoder) + else: + kwargs.setdefault('cls', JSONDecoder) + + +def dumps(obj, **kwargs): + """Serialize ``obj`` to a JSON formatted ``str`` by using the application's + configured encoder (:attr:`~flask.Flask.json_encoder`) if there is an + application on the stack. + + This function can return ``unicode`` strings or ascii-only bytestrings by + default which coerce into unicode strings automatically. That behavior by + default is controlled by the ``JSON_AS_ASCII`` configuration variable + and can be overridden by the simplejson ``ensure_ascii`` parameter. + """ + _dump_arg_defaults(kwargs) + encoding = kwargs.pop('encoding', None) + rv = _json.dumps(obj, **kwargs) + if encoding is not None and isinstance(rv, text_type): + rv = rv.encode(encoding) + return rv + + +def dump(obj, fp, **kwargs): + """Like :func:`dumps` but writes into a file object.""" + _dump_arg_defaults(kwargs) + encoding = kwargs.pop('encoding', None) + if encoding is not None: + fp = _wrap_writer_for_text(fp, encoding) + _json.dump(obj, fp, **kwargs) + + +def loads(s, **kwargs): + """Unserialize a JSON object from a string ``s`` by using the application's + configured decoder (:attr:`~flask.Flask.json_decoder`) if there is an + application on the stack. + """ + _load_arg_defaults(kwargs) + if isinstance(s, bytes): + s = s.decode(kwargs.pop('encoding', None) or 'utf-8') + return _json.loads(s, **kwargs) + + +def load(fp, **kwargs): + """Like :func:`loads` but reads from a file object. + """ + _load_arg_defaults(kwargs) + if not PY2: + fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8') + return _json.load(fp, **kwargs) + + +def htmlsafe_dumps(obj, **kwargs): + """Works exactly like :func:`dumps` but is safe for use in ``') + # => <script> do_nasty_stuff() </script> + # sanitize_html('Click here for $100') + # => Click here for $100 + def sanitize_token(self, token): + + # accommodate filters which use token_type differently + token_type = token["type"] + if token_type in ("StartTag", "EndTag", "EmptyTag"): + name = token["name"] + namespace = token["namespace"] + if ((namespace, name) in self.allowed_elements or + (namespace is None and + (namespaces["html"], name) in self.allowed_elements)): + return self.allowed_token(token) + else: + return self.disallowed_token(token) + elif token_type == "Comment": + pass + else: + return token + + def allowed_token(self, token): + if "data" in token: + attrs = token["data"] + attr_names = set(attrs.keys()) + + # Remove forbidden attributes + for to_remove in (attr_names - self.allowed_attributes): + del token["data"][to_remove] + attr_names.remove(to_remove) + + # Remove attributes with disallowed URL values + for attr in (attr_names & self.attr_val_is_uri): + assert attr in attrs + # I don't have a clue where this regexp comes from or why it matches those + # characters, nor why we call unescape. I just know it's always been here. + # Should you be worried by this comment in a sanitizer? Yes. On the other hand, all + # this will do is remove *more* than it otherwise would. + val_unescaped = re.sub("[`\x00-\x20\x7f-\xa0\s]+", '', + unescape(attrs[attr])).lower() + # remove replacement characters from unescaped characters + val_unescaped = val_unescaped.replace("\ufffd", "") + try: + uri = urlparse.urlparse(val_unescaped) + except ValueError: + uri = None + del attrs[attr] + if uri and uri.scheme: + if uri.scheme not in self.allowed_protocols: + del attrs[attr] + if uri.scheme == 'data': + m = data_content_type.match(uri.path) + if not m: + del attrs[attr] + elif m.group('content_type') not in self.allowed_content_types: + del attrs[attr] + + for attr in self.svg_attr_val_allows_ref: + if attr in attrs: + attrs[attr] = re.sub(r'url\s*\(\s*[^#\s][^)]+?\)', + ' ', + unescape(attrs[attr])) + if (token["name"] in self.svg_allow_local_href and + (namespaces['xlink'], 'href') in attrs and re.search('^\s*[^#\s].*', + attrs[(namespaces['xlink'], 'href')])): + del attrs[(namespaces['xlink'], 'href')] + if (None, 'style') in attrs: + attrs[(None, 'style')] = self.sanitize_css(attrs[(None, 'style')]) + token["data"] = attrs + return token + + def disallowed_token(self, token): + token_type = token["type"] + if token_type == "EndTag": + token["data"] = "" % token["name"] + elif token["data"]: + assert token_type in ("StartTag", "EmptyTag") + attrs = [] + for (ns, name), v in token["data"].items(): + attrs.append(' %s="%s"' % (name if ns is None else "%s:%s" % (prefixes[ns], name), escape(v))) + token["data"] = "<%s%s>" % (token["name"], ''.join(attrs)) + else: + token["data"] = "<%s>" % token["name"] + if token.get("selfClosing"): + token["data"] = token["data"][:-1] + "/>" + + token["type"] = "Characters" + + del token["name"] + return token + + def sanitize_css(self, style): + # disallow urls + style = re.compile('url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ', style) + + # gauntlet + if not re.match("""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): + return '' + if not re.match("^\s*([-\w]+\s*:[^:;]*(;\s*|$))*$", style): + return '' + + clean = [] + for prop, value in re.findall("([-\w]+)\s*:\s*([^:;]*)", style): + if not value: + continue + if prop.lower() in self.allowed_css_properties: + clean.append(prop + ': ' + value + ';') + elif prop.split('-')[0].lower() in ['background', 'border', 'margin', + 'padding']: + for keyword in value.split(): + if keyword not in self.allowed_css_keywords and \ + not re.match("^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$", keyword): # noqa + break + else: + clean.append(prop + ': ' + value + ';') + elif prop.lower() in self.allowed_svg_properties: + clean.append(prop + ': ' + value + ';') + + return ' '.join(clean) diff --git a/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/sanitizer.pyc b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/sanitizer.pyc new file mode 100644 index 0000000..38276fc Binary files /dev/null and b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/sanitizer.pyc differ diff --git a/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.py b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.py new file mode 100644 index 0000000..8921052 --- /dev/null +++ b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.py @@ -0,0 +1,38 @@ +from __future__ import absolute_import, division, unicode_literals + +import re + +from . import base +from ..constants import rcdataElements, spaceCharacters +spaceCharacters = "".join(spaceCharacters) + +SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) + + +class Filter(base.Filter): + + spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) + + def __iter__(self): + preserve = 0 + for token in base.Filter.__iter__(self): + type = token["type"] + if type == "StartTag" \ + and (preserve or token["name"] in self.spacePreserveElements): + preserve += 1 + + elif type == "EndTag" and preserve: + preserve -= 1 + + elif not preserve and type == "SpaceCharacters" and token["data"]: + # Test on token["data"] above to not introduce spaces where there were not + token["data"] = " " + + elif not preserve and type == "Characters": + token["data"] = collapse_spaces(token["data"]) + + yield token + + +def collapse_spaces(text): + return SPACES_REGEX.sub(' ', text) diff --git a/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.pyc b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.pyc new file mode 100644 index 0000000..84ba118 Binary files /dev/null and b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/filters/whitespace.pyc differ diff --git a/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/html5parser.py b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/html5parser.py new file mode 100644 index 0000000..f7043cb --- /dev/null +++ b/venv/lib/python2.7/site-packages/pip/_vendor/html5lib/html5parser.py @@ -0,0 +1,2733 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import with_metaclass, viewkeys, PY3 + +import types + +try: + from collections import OrderedDict +except ImportError: + from pip._vendor.ordereddict import OrderedDict + +from . import _inputstream +from . import _tokenizer + +from . import treebuilders +from .treebuilders.base import Marker + +from . import _utils +from .constants import ( + spaceCharacters, asciiUpper2Lower, + specialElements, headingElements, cdataElements, rcdataElements, + tokenTypes, tagTokenTypes, + namespaces, + htmlIntegrationPointElements, mathmlTextIntegrationPointElements, + adjustForeignAttributes as adjustForeignAttributesMap, + adjustMathMLAttributes, adjustSVGAttributes, + E, + ReparseException +) + + +def parse(doc, treebuilder="etree", namespaceHTMLElements=True, **kwargs): + """Parse a string or file-like object into a tree""" + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parse(doc, **kwargs) + + +def parseFragment(doc, container="div", treebuilder="etree", namespaceHTMLElements=True, **kwargs): + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parseFragment(doc, container=container, **kwargs) + + +def method_decorator_metaclass(function): + class Decorated(type): + def __new__(meta, classname, bases, classDict): + for attributeName, attribute in classDict.items(): + if isinstance(attribute, types.FunctionType): + attribute = function(attribute) + + classDict[attributeName] = attribute + return type.__new__(meta, classname, bases, classDict) + return Decorated + + +class HTMLParser(object): + """HTML parser. Generates a tree structure from a stream of (possibly + malformed) HTML""" + + def __init__(self, tree=None, strict=False, namespaceHTMLElements=True, debug=False): + """ + strict - raise an exception when a parse error is encountered + + tree - a treebuilder class controlling the type of tree that will be + returned. Built in treebuilders can be accessed through + html5lib.treebuilders.getTreeBuilder(treeType) + """ + + # Raise an exception on the first error encountered + self.strict = strict + + if tree is None: + tree = treebuilders.getTreeBuilder("etree") + self.tree = tree(namespaceHTMLElements) + self.errors = [] + + self.phases = dict([(name, cls(self, self.tree)) for name, cls in + getPhases(debug).items()]) + + def _parse(self, stream, innerHTML=False, container="div", scripting=False, **kwargs): + + self.innerHTMLMode = innerHTML + self.container = container + self.scripting = scripting + self.tokenizer = _tokenizer.HTMLTokenizer(stream, parser=self, **kwargs) + self.reset() + + try: + self.mainLoop() + except ReparseException: + self.reset() + self.mainLoop() + + def reset(self): + self.tree.reset() + self.firstStartTag = False + self.errors = [] + self.log = [] # only used with debug mode + # "quirks" / "limited quirks" / "no quirks" + self.compatMode = "no quirks" + + if self.innerHTMLMode: + self.innerHTML = self.container.lower() + + if self.innerHTML in cdataElements: + self.tokenizer.state = self.tokenizer.rcdataState + elif self.innerHTML in rcdataElements: + self.tokenizer.state = self.tokenizer.rawtextState + elif self.innerHTML == 'plaintext': + self.tokenizer.state = self.tokenizer.plaintextState + else: + # state already is data state + # self.tokenizer.state = self.tokenizer.dataState + pass + self.phase = self.phases["beforeHtml"] + self.phase.insertHtmlElement() + self.resetInsertionMode() + else: + self.innerHTML = False # pylint:disable=redefined-variable-type + self.phase = self.phases["initial"] + + self.lastPhase = None + + self.beforeRCDataPhase = None + + self.framesetOK = True + + @property + def documentEncoding(self): + """The name of the character encoding + that was used to decode the input stream, + or :obj:`None` if that is not determined yet. + + """ + if not hasattr(self, 'tokenizer'): + return None + return self.tokenizer.stream.charEncoding[0].name + + def isHTMLIntegrationPoint(self, element): + if (element.name == "annotation-xml" and + element.namespace == namespaces["mathml"]): + return ("encoding" in element.attributes and + element.attributes["encoding"].translate( + asciiUpper2Lower) in + ("text/html", "application/xhtml+xml")) + else: + return (element.namespace, element.name) in htmlIntegrationPointElements + + def isMathMLTextIntegrationPoint(self, element): + return (element.namespace, element.name) in mathmlTextIntegrationPointElements + + def mainLoop(self): + CharactersToken = tokenTypes["Characters"] + SpaceCharactersToken = tokenTypes["SpaceCharacters"] + StartTagToken = tokenTypes["StartTag"] + EndTagToken = tokenTypes["EndTag"] + CommentToken = tokenTypes["Comment"] + DoctypeToken = tokenTypes["Doctype"] + ParseErrorToken = tokenTypes["ParseError"] + + for token in self.normalizedTokens(): + prev_token = None + new_token = token + while new_token is not None: + prev_token = new_token + currentNode = self.tree.openElements[-1] if self.tree.openElements else None + currentNodeNamespace = currentNode.namespace if currentNode else None + currentNodeName = currentNode.name if currentNode else None + + type = new_token["type"] + + if type == ParseErrorToken: + self.parseError(new_token["data"], new_token.get("datavars", {})) + new_token = None + else: + if (len(self.tree.openElements) == 0 or + currentNodeNamespace == self.tree.defaultNamespace or + (self.isMathMLTextIntegrationPoint(currentNode) and + ((type == StartTagToken and + token["name"] not in frozenset(["mglyph", "malignmark"])) or + type in (CharactersToken, SpaceCharactersToken))) or + (currentNodeNamespace == namespaces["mathml"] and + currentNodeName == "annotation-xml" and + type == StartTagToken and + token["name"] == "svg") or + (self.isHTMLIntegrationPoint(currentNode) and + type in (StartTagToken, CharactersToken, SpaceCharactersToken))): + phase = self.phase + else: + phase = self.phases["inForeignContent"] + + if type == CharactersToken: + new_token = phase.processCharacters(new_token) + elif type == SpaceCharactersToken: + new_token = phase.processSpaceCharacters(new_token) + elif type == StartTagToken: + new_token = phase.processStartTag(new_token) + elif type == EndTagToken: + new_token = phase.processEndTag(new_token) + elif type == CommentToken: + new_token = phase.processComment(new_token) + elif type == DoctypeToken: + new_token = phase.processDoctype(new_token) + + if (type == StartTagToken and prev_token["selfClosing"] and + not prev_token["selfClosingAcknowledged"]): + self.parseError("non-void-element-with-trailing-solidus", + {"name": prev_token["name"]}) + + # When the loop finishes it's EOF + reprocess = True + phases = [] + while reprocess: + phases.append(self.phase) + reprocess = self.phase.processEOF() + if reprocess: + assert self.phase not in phases + + def normalizedTokens(self): + for token in self.tokenizer: + yield self.normalizeToken(token) + + def parse(self, stream, *args, **kwargs): + """Parse a HTML document into a well-formed tree + + stream - a filelike object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + scripting - treat noscript elements as if javascript was turned on + """ + self._parse(stream, False, None, *args, **kwargs) + return self.tree.getDocument() + + def parseFragment(self, stream, *args, **kwargs): + """Parse a HTML fragment into a well-formed tree fragment + + container - name of the element we're setting the innerHTML property + if set to None, default to 'div' + + stream - a filelike object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + scripting - treat noscript elements as if javascript was turned on + """ + self._parse(stream, True, *args, **kwargs) + return self.tree.getFragment() + + def parseError(self, errorcode="XXX-undefined-error", datavars=None): + # XXX The idea is to make errorcode mandatory. + if datavars is None: + datavars = {} + self.errors.append((self.tokenizer.stream.position(), errorcode, datavars)) + if self.strict: + raise ParseError(E[errorcode] % datavars) + + def normalizeToken(self, token): + """ HTML5 specific normalizations to the token stream """ + + if token["type"] == tokenTypes["StartTag"]: + raw = token["data"] + token["data"] = OrderedDict(raw) + if len(raw) > len(token["data"]): + # we had some duplicated attribute, fix so first wins + token["data"].update(raw[::-1]) + + return token + + def adjustMathMLAttributes(self, token): + adjust_attributes(token, adjustMathMLAttributes) + + def adjustSVGAttributes(self, token): + adjust_attributes(token, adjustSVGAttributes) + + def adjustForeignAttributes(self, token): + adjust_attributes(token, adjustForeignAttributesMap) + + def reparseTokenNormal(self, token): + # pylint:disable=unused-argument + self.parser.phase() + + def resetInsertionMode(self): + # The name of this method is mostly historical. (It's also used in the + # specification.) + last = False + newModes = { + "select": "inSelect", + "td": "inCell", + "th": "inCell", + "tr": "inRow", + "tbody": "inTableBody", + "thead": "inTableBody", + "tfoot": "inTableBody", + "caption": "inCaption", + "colgroup": "inColumnGroup", + "table": "inTable", + "head": "inBody", + "body": "inBody", + "frameset": "inFrameset", + "html": "beforeHead" + } + for node in self.tree.openElements[::-1]: + nodeName = node.name + new_phase = None + if node == self.tree.openElements[0]: + assert self.innerHTML + last = True + nodeName = self.innerHTML + # Check for conditions that should only happen in the innerHTML + # case + if nodeName in ("select", "colgroup", "head", "html"): + assert self.innerHTML + + if not last and node.namespace != self.tree.defaultNamespace: + continue + + if nodeName in newModes: + new_phase = self.phases[newModes[nodeName]] + break + elif last: + new_phase = self.phases["inBody"] + break + + self.phase = new_phase + + def parseRCDataRawtext(self, token, contentType): + """Generic RCDATA/RAWTEXT Parsing algorithm + contentType - RCDATA or RAWTEXT + """ + assert contentType in ("RAWTEXT", "RCDATA") + + self.tree.insertElement(token) + + if contentType == "RAWTEXT": + self.tokenizer.state = self.tokenizer.rawtextState + else: + self.tokenizer.state = self.tokenizer.rcdataState + + self.originalPhase = self.phase + + self.phase = self.phases["text"] + + +@_utils.memoize +def getPhases(debug): + def log(function): + """Logger that records which phase processes each token""" + type_names = dict((value, key) for key, value in + tokenTypes.items()) + + def wrapped(self, *args, **kwargs): + if function.__name__.startswith("process") and len(args) > 0: + token = args[0] + try: + info = {"type": type_names[token['type']]} + except: + raise + if token['type'] in tagTokenTypes: + info["name"] = token['name'] + + self.parser.log.append((self.parser.tokenizer.state.__name__, + self.parser.phase.__class__.__name__, + self.__class__.__name__, + function.__name__, + info)) + return function(self, *args, **kwargs) + else: + return function(self, *args, **kwargs) + return wrapped + + def getMetaclass(use_metaclass, metaclass_func): + if use_metaclass: + return method_decorator_metaclass(metaclass_func) + else: + return type + + # pylint:disable=unused-argument + class Phase(with_metaclass(getMetaclass(debug, log))): + """Base class for helper object that implements each phase of processing + """ + + def __init__(self, parser, tree): + self.parser = parser + self.tree = tree + + def processEOF(self): + raise NotImplementedError + + def processComment(self, token): + # For most phases the following is correct. Where it's not it will be + # overridden. + self.tree.insertComment(token, self.tree.openElements[-1]) + + def processDoctype(self, token): + self.parser.parseError("unexpected-doctype") + + def processCharacters(self, token): + self.tree.insertText(token["data"]) + + def processSpaceCharacters(self, token): + self.tree.insertText(token["data"]) + + def processStartTag(self, token): + return self.startTagHandler[token["name"]](token) + + def startTagHtml(self, token): + if not self.parser.firstStartTag and token["name"] == "html": + self.parser.parseError("non-html-root") + # XXX Need a check here to see if the first start tag token emitted is + # this token... If it's not, invoke self.parser.parseError(). + for attr, value in token["data"].items(): + if attr not in self.tree.openElements[0].attributes: + self.tree.openElements[0].attributes[attr] = value + self.parser.firstStartTag = False + + def processEndTag(self, token): + return self.endTagHandler[token["name"]](token) + + class InitialPhase(Phase): + def processSpaceCharacters(self, token): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + correct = token["correct"] + + if (name != "html" or publicId is not None or + systemId is not None and systemId != "about:legacy-compat"): + self.parser.parseError("unknown-doctype") + + if publicId is None: + publicId = "" + + self.tree.insertDoctype(token) + + if publicId != "": + publicId = publicId.translate(asciiUpper2Lower) + + if (not correct or token["name"] != "html" or + publicId.startswith( + ("+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//")) or + publicId in ("-//w3o//dtd w3 html strict 3.0//en//", + "-/w3c/dtd html 4.0 transitional/en", + "html") or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is None or + systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"): + self.parser.compatMode = "quirks" + elif (publicId.startswith( + ("-//w3c//dtd xhtml 1.0 frameset//", + "-//w3c//dtd xhtml 1.0 transitional//")) or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is not None): + self.parser.compatMode = "limited quirks" + + self.parser.phase = self.parser.phases["beforeHtml"] + + def anythingElse(self): + self.parser.compatMode = "quirks" + self.parser.phase = self.parser.phases["beforeHtml"] + + def processCharacters(self, token): + self.parser.parseError("expected-doctype-but-got-chars") + self.anythingElse() + return token + + def processStartTag(self, token): + self.parser.parseError("expected-doctype-but-got-start-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEndTag(self, token): + self.parser.parseError("expected-doctype-but-got-end-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEOF(self): + self.parser.parseError("expected-doctype-but-got-eof") + self.anythingElse() + return True + + class BeforeHtmlPhase(Phase): + # helper methods + def insertHtmlElement(self): + self.tree.insertRoot(impliedTagToken("html", "StartTag")) + self.parser.phase = self.parser.phases["beforeHead"] + + # other + def processEOF(self): + self.insertHtmlElement() + return True + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.insertHtmlElement() + return token + + def processStartTag(self, token): + if token["name"] == "html": + self.parser.firstStartTag = True + self.insertHtmlElement() + return token + + def processEndTag(self, token): + if token["name"] not in ("head", "body", "html", "br"): + self.parser.parseError("unexpected-end-tag-before-html", + {"name": token["name"]}) + else: + self.insertHtmlElement() + return token + + class BeforeHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("head", "body", "html", "br"), self.endTagImplyHead) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.startTagHead(impliedTagToken("head", "StartTag")) + return True + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.tree.insertElement(token) + self.tree.headPointer = self.tree.openElements[-1] + self.parser.phase = self.parser.phases["inHead"] + + def startTagOther(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagImplyHead(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagOther(self, token): + self.parser.parseError("end-tag-after-implied-root", + {"name": token["name"]}) + + class InHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("title", self.startTagTitle), + (("noframes", "style"), self.startTagNoFramesStyle), + ("noscript", self.startTagNoscript), + ("script", self.startTagScript), + (("base", "basefont", "bgsound", "command", "link"), + self.startTagBaseLinkCommand), + ("meta", self.startTagMeta), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("head", self.endTagHead), + (("br", "html", "body"), self.endTagHtmlBodyBr) + ]) + self.endTagHandler.default = self.endTagOther + + # the real thing + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.parser.parseError("two-heads-are-not-better-than-one") + + def startTagBaseLinkCommand(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagMeta(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + attributes = token["data"] + if self.parser.tokenizer.stream.charEncoding[1] == "tentative": + if "charset" in attributes: + self.parser.tokenizer.stream.changeEncoding(attributes["charset"]) + elif ("content" in attributes and + "http-equiv" in attributes and + attributes["http-equiv"].lower() == "content-type"): + # Encoding it as UTF-8 here is a hack, as really we should pass + # the abstract Unicode string, and just use the + # ContentAttrParser on that, but using UTF-8 allows all chars + # to be encoded and as a ASCII-superset works. + data = _inputstream.EncodingBytes(attributes["content"].encode("utf-8")) + parser = _inputstream.ContentAttrParser(data) + codec = parser.parse() + self.parser.tokenizer.stream.changeEncoding(codec) + + def startTagTitle(self, token): + self.parser.parseRCDataRawtext(token, "RCDATA") + + def startTagNoFramesStyle(self, token): + # Need to decide whether to implement the scripting-disabled case + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagNoscript(self, token): + if self.parser.scripting: + self.parser.parseRCDataRawtext(token, "RAWTEXT") + else: + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inHeadNoscript"] + + def startTagScript(self, token): + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState + self.parser.originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["text"] + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHead(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "head", "Expected head got %s" % node.name + self.parser.phase = self.parser.phases["afterHead"] + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.endTagHead(impliedTagToken("head")) + + class InHeadNoscriptPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("basefont", "bgsound", "link", "meta", "noframes", "style"), self.startTagBaseLinkCommand), + (("head", "noscript"), self.startTagHeadNoscript), + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("noscript", self.endTagNoscript), + ("br", self.endTagBr), + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.parser.parseError("eof-in-head-noscript") + self.anythingElse() + return True + + def processComment(self, token): + return self.parser.phases["inHead"].processComment(token) + + def processCharacters(self, token): + self.parser.parseError("char-in-head-noscript") + self.anythingElse() + return token + + def processSpaceCharacters(self, token): + return self.parser.phases["inHead"].processSpaceCharacters(token) + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBaseLinkCommand(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagHeadNoscript(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagNoscript(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "noscript", "Expected noscript got %s" % node.name + self.parser.phase = self.parser.phases["inHead"] + + def endTagBr(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + # Caller must raise parse error first! + self.endTagNoscript(impliedTagToken("noscript")) + + class AfterHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("body", self.startTagBody), + ("frameset", self.startTagFrameset), + (("base", "basefont", "bgsound", "link", "meta", "noframes", "script", + "style", "title"), + self.startTagFromHead), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + self.endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"), + self.endTagHtmlBodyBr)]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBody(self, token): + self.parser.framesetOK = False + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inBody"] + + def startTagFrameset(self, token): + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inFrameset"] + + def startTagFromHead(self, token): + self.parser.parseError("unexpected-start-tag-out-of-my-head", + {"name": token["name"]}) + self.tree.openElements.append(self.tree.headPointer) + self.parser.phases["inHead"].processStartTag(token) + for node in self.tree.openElements[::-1]: + if node.name == "head": + self.tree.openElements.remove(node) + break + + def startTagHead(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.tree.insertElement(impliedTagToken("body", "StartTag")) + self.parser.phase = self.parser.phases["inBody"] + self.parser.framesetOK = True + + class InBodyPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody + # the really-really-really-very crazy mode + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + # Set this to the default handler + self.processSpaceCharacters = self.processSpaceCharactersNonPre + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("base", "basefont", "bgsound", "command", "link", "meta", + "script", "style", "title"), + self.startTagProcessInHead), + ("body", self.startTagBody), + ("frameset", self.startTagFrameset), + (("address", "article", "aside", "blockquote", "center", "details", + "dir", "div", "dl", "fieldset", "figcaption", "figure", + "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p", + "section", "summary", "ul"), + self.startTagCloseP), + (headingElements, self.startTagHeading), + (("pre", "listing"), self.startTagPreListing), + ("form", self.startTagForm), + (("li", "dd", "dt"), self.startTagListItem), + ("plaintext", self.startTagPlaintext), + ("a", self.startTagA), + (("b", "big", "code", "em", "font", "i", "s", "small", "strike", + "strong", "tt", "u"), self.startTagFormatting), + ("nobr", self.startTagNobr), + ("button", self.startTagButton), + (("applet", "marquee", "object"), self.startTagAppletMarqueeObject), + ("xmp", self.startTagXmp), + ("table", self.startTagTable), + (("area", "br", "embed", "img", "keygen", "wbr"), + self.startTagVoidFormatting), + (("param", "source", "track"), self.startTagParamSource), + ("input", self.startTagInput), + ("hr", self.startTagHr), + ("image", self.startTagImage), + ("isindex", self.startTagIsIndex), + ("textarea", self.startTagTextarea), + ("iframe", self.startTagIFrame), + ("noscript", self.startTagNoscript), + (("noembed", "noframes"), self.startTagRawtext), + ("select", self.startTagSelect), + (("rp", "rt"), self.startTagRpRt), + (("option", "optgroup"), self.startTagOpt), + (("math"), self.startTagMath), + (("svg"), self.startTagSvg), + (("caption", "col", "colgroup", "frame", "head", + "tbody", "td", "tfoot", "th", "thead", + "tr"), self.startTagMisplaced) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("body", self.endTagBody), + ("html", self.endTagHtml), + (("address", "article", "aside", "blockquote", "button", "center", + "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", + "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre", + "section", "summary", "ul"), self.endTagBlock), + ("form", self.endTagForm), + ("p", self.endTagP), + (("dd", "dt", "li"), self.endTagListItem), + (headingElements, self.endTagHeading), + (("a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", + "strike", "strong", "tt", "u"), self.endTagFormatting), + (("applet", "marquee", "object"), self.endTagAppletMarqueeObject), + ("br", self.endTagBr), + ]) + self.endTagHandler.default = self.endTagOther + + def isMatchingFormattingElement(self, node1, node2): + return (node1.name == node2.name and + node1.namespace == node2.namespace and + node1.attributes == node2.attributes) + + # helper + def addFormattingElement(self, token): + self.tree.insertElement(token) + element = self.tree.openElements[-1] + + matchingElements = [] + for node in self.tree.activeFormattingElements[::-1]: + if node is Marker: + break + elif self.isMatchingFormattingElement(node, element): + matchingElements.append(node) + + assert len(matchingElements) <= 3 + if len(matchingElements) == 3: + self.tree.activeFormattingElements.remove(matchingElements[-1]) + self.tree.activeFormattingElements.append(element) + + # the real deal + def processEOF(self): + allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td", + "tfoot", "th", "thead", "tr", "body", + "html")) + for node in self.tree.openElements[::-1]: + if node.name not in allowed_elements: + self.parser.parseError("expected-closing-tag-but-got-eof") + break + # Stop parsing + + def processSpaceCharactersDropNewline(self, token): + # Sometimes (start of

, , and ",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/\s*$/g,ra={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?""!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("