├── labs ├── solutions │ ├── exercise2 │ │ ├── hello │ │ └── hello.py │ ├── exercise5 │ │ ├── pycon │ │ │ ├── __init__.py │ │ │ ├── xmath.py │ │ │ └── bank.py │ │ └── main.py │ ├── exercise8 │ │ ├── pickle │ │ │ ├── __init__.py │ │ │ └── models.py │ │ ├── shelve │ │ │ ├── __init__.py │ │ │ └── models.py │ │ └── sql │ │ │ └── dvds.py │ ├── exercise10 │ │ └── mysite │ │ │ ├── mysite │ │ │ ├── __init__.py │ │ │ ├── urls.py │ │ │ ├── wsgi.py │ │ │ └── settings.py │ │ │ ├── polls │ │ │ ├── __init__.py │ │ │ ├── views.py │ │ │ ├── tests.py │ │ │ └── models.py │ │ │ ├── db.sqlite3 │ │ │ └── manage.py │ ├── exercise11 │ │ └── mysite │ │ │ ├── mysite │ │ │ ├── __init__.py │ │ │ ├── urls.py │ │ │ ├── wsgi.py │ │ │ └── settings.py │ │ │ ├── polls │ │ │ ├── __init__.py │ │ │ ├── tests.py │ │ │ ├── urls.py │ │ │ ├── views.py │ │ │ └── models.py │ │ │ ├── db.sqlite3 │ │ │ └── manage.py │ ├── exercise12 │ │ └── mysite │ │ │ ├── mysite │ │ │ ├── __init__.py │ │ │ ├── urls.py │ │ │ ├── wsgi.py │ │ │ └── settings.py │ │ │ ├── polls │ │ │ ├── __init__.py │ │ │ ├── templates │ │ │ │ └── polls │ │ │ │ │ ├── detail.html │ │ │ │ │ └── index.html │ │ │ ├── tests.py │ │ │ ├── urls.py │ │ │ ├── models.py │ │ │ └── views.py │ │ │ ├── db.sqlite3 │ │ │ └── manage.py │ ├── exercise13 │ │ └── mysite │ │ │ ├── mysite │ │ │ ├── __init__.py │ │ │ ├── urls.py │ │ │ ├── wsgi.py │ │ │ └── settings.py │ │ │ ├── polls │ │ │ ├── __init__.py │ │ │ ├── templates │ │ │ │ └── polls │ │ │ │ │ ├── index.html │ │ │ │ │ ├── results.html │ │ │ │ │ └── detail.html │ │ │ ├── tests.py │ │ │ ├── urls.py │ │ │ ├── models.py │ │ │ └── views.py │ │ │ ├── db.sqlite3 │ │ │ └── manage.py │ ├── exercise9 │ │ └── mysite │ │ │ ├── mysite │ │ │ ├── __init__.py │ │ │ ├── urls.py │ │ │ ├── wsgi.py │ │ │ └── settings.py │ │ │ └── manage.py │ ├── exercise4 │ │ ├── exercise4-1.py │ │ └── exercise4-2.py │ ├── exercise6 │ │ └── main.py │ ├── exercise14 │ │ ├── util_test.txt │ │ └── util.py │ ├── exercise7 │ │ └── main.py │ └── exercise15 │ │ ├── test_dvdlib.py │ │ └── dvdlib.py ├── exercises │ ├── exercise8 │ │ ├── pickle │ │ │ ├── __init__.py │ │ │ └── models.py │ │ ├── shelve │ │ │ ├── __init__.py │ │ │ └── models.py │ │ └── sql │ │ │ └── dvds.py │ ├── exercise6 │ │ └── main.py │ ├── exercise4 │ │ ├── exercise4-1.py │ │ └── exercise4-2.py │ ├── exercise14 │ │ └── util.py │ ├── exercise7 │ │ └── main.py │ ├── exercise15 │ │ ├── test_dvdlib.py │ │ └── dvdlib.py │ └── exercise5 │ │ └── main.py ├── resources │ ├── Hell0_zh_TW.txt │ ├── python-tk.txt │ ├── chewing.txt │ ├── git.txt │ ├── django.txt │ └── distribute_setup.py └── demos │ ├── cProfile │ ├── profile_sorting.py │ └── sorting.py │ └── timeit │ ├── sorting.py │ ├── timeit_sorting.py │ └── sorting-Justin-2012.py ├── Instructor.txt ├── PyCon Taiwan 2013 Tutorial.pdf ├── PyCon Taiwan 2013 Tutorial.pptx ├── tutorial └── images │ ├── python-tutorial-the-4th-class-1.png │ ├── python-tutorial-the-4th-class-2.png │ ├── python-tutorial-the-4th-class-3.png │ ├── python-tutorial-the-4th-class-4.png │ ├── python-tutorial-the-4th-class-5.png │ ├── python-tutorial-the-4th-class-6.png │ ├── python-tutorial-the-4th-class-7.png │ ├── python-tutorial-the-4th-class-8.png │ ├── python-tutorial-the-1st-class-2-1.jpg │ ├── python-tutorial-the-1st-class-2-2.jpg │ ├── python-tutorial-the-1st-class-3-1.jpg │ ├── python-tutorial-the-1st-class-3-2.jpg │ ├── python-tutorial-the-2nd-class-3-1.png │ ├── python-tutorial-the-2nd-class-3-2.png │ ├── python-tutorial-the-4th-class-2-1.png │ ├── python-tutorial-the-4th-class-2-2.png │ ├── python-tutorial-the-4th-class-2-3.png │ ├── python-tutorial-the-4th-class-2-4.png │ ├── python-tutorial-the-4th-class-2-5.png │ ├── python-tutorial-the-4th-class-3-1.png │ ├── python-tutorial-the-4th-class-3-2.png │ ├── python-tutorial-the-4th-class-3-3.png │ ├── python-tutorial-the-5th-class-1-1.PNG │ ├── python-tutorial-the-5th-class-1-2.PNG │ ├── python-tutorial-the-5th-class-1-3.PNG │ ├── python-tutorial-the-5th-class-1-4.PNG │ ├── python-tutorial-the-5th-class-2-1.PNG │ ├── python-tutorial-the-5th-class-2-2.PNG │ ├── python-tutorial-the-5th-class-2-3.PNG │ ├── python-tutorial-the-5th-class-2-4.PNG │ ├── python-tutorial-the-5th-class-2-5.PNG │ ├── python-tutorial-the-5th-class-2-6.PNG │ ├── python-tutorial-the-5th-class-2-7.PNG │ ├── python-tutorial-the-5th-class-2-8.PNG │ ├── python-tutorial-the-5th-class-2-9.PNG │ ├── python-tutorial-the-5th-class-3-1.png │ ├── python-tutorial-the-5th-class-3-2.png │ ├── python-tutorial-the-5th-class-3-3.png │ ├── python-tutorial-the-6th-class-1-1.png │ ├── python-tutorial-the-6th-class-1-2.png │ ├── python-tutorial-the-6th-class-1-3.png │ ├── python-tutorial-the-6th-class-1-4.png │ ├── python-tutorial-the-6th-class-2-1.png │ ├── python-tutorial-the-6th-class-2-2.png │ ├── python-tutorial-the-6th-class-2-3.png │ ├── python-tutorial-the-6th-class-2-4.png │ ├── python-tutorial-the-6th-class-2-5.png │ ├── python-tutorial-the-6th-class-2-6.png │ ├── python-tutorial-the-6th-class-2-7.png │ ├── python-tutorial-the-6th-class-2-8.png │ ├── python-tutorial-the-3rd-class-3-1-300x178.png │ ├── functional-programming-for-java-developers-reduce.gif │ ├── python-tutorial-the-3rd-class-community-documentation-1.png │ ├── python-tutorial-the-3rd-class-community-documentation-2.png │ ├── python-tutorial-the-3rd-class-community-documentation-3.png │ ├── python-tutorial-the-3rd-class-community-documentation-4.png │ ├── python-tutorial-the-3rd-class-community-documentation-5.png │ ├── python-tutorial-the-3rd-class-community-documentation-6.png │ ├── python-tutorial-the-3rd-class-community-documentation-7.png │ ├── python-tutorial-the-3rd-class-community-documentation-8.png │ └── python-tutorial-the-1st-class-4-unicode-support-basic-input-output-1.jpg ├── .gitattributes ├── schedule.txt ├── .gitignore ├── README.md └── LICENSE /labs/solutions/exercise2/hello: -------------------------------------------------------------------------------- 1 | 哈囉!世界! -------------------------------------------------------------------------------- /labs/exercises/exercise8/pickle/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/exercises/exercise8/shelve/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise5/pycon/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise8/pickle/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise8/shelve/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/resources/Hell0_zh_TW.txt: -------------------------------------------------------------------------------- 1 | 檔名: 2 | 哈囉!世界! -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/mysite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/polls/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/mysite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/polls/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/mysite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/polls/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/mysite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/solutions/exercise9/mysite/mysite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /labs/resources/python-tk.txt: -------------------------------------------------------------------------------- 1 | sudo apt-get install python-tk -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/polls/views.py: -------------------------------------------------------------------------------- 1 | # Create your views here. 2 | -------------------------------------------------------------------------------- /Instructor.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/Instructor.txt -------------------------------------------------------------------------------- /labs/solutions/exercise4/exercise4-1.py: -------------------------------------------------------------------------------- 1 | print ", ".join([str(number) for number in range(20)]) -------------------------------------------------------------------------------- /labs/resources/chewing.txt: -------------------------------------------------------------------------------- 1 | sudo apt-get install scim scim-chewing; sudo im-switch -s scim-bridge 2 | ibus-setup -------------------------------------------------------------------------------- /labs/resources/git.txt: -------------------------------------------------------------------------------- 1 | sudo apt-get install git 2 | git clone https://github.com/JustinSDK/PyConTW2013Tutorial.git 3 | -------------------------------------------------------------------------------- /PyCon Taiwan 2013 Tutorial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/PyCon Taiwan 2013 Tutorial.pdf -------------------------------------------------------------------------------- /PyCon Taiwan 2013 Tutorial.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/PyCon Taiwan 2013 Tutorial.pptx -------------------------------------------------------------------------------- /labs/exercises/exercise6/main.py: -------------------------------------------------------------------------------- 1 | names = ['Justin', 'caterpillar', 'openhome'] 2 | for ______ in ______: 3 | print '{0}, {1}'.format(______) -------------------------------------------------------------------------------- /labs/exercises/exercise4/exercise4-1.py: -------------------------------------------------------------------------------- 1 | numbers = [] 2 | for number in range(20): 3 | numbers.append(str(number)) 4 | print ", ".join(numbers) -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/labs/solutions/exercise10/mysite/db.sqlite3 -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/labs/solutions/exercise11/mysite/db.sqlite3 -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/labs/solutions/exercise12/mysite/db.sqlite3 -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/labs/solutions/exercise13/mysite/db.sqlite3 -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-3.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-4.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-5.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-6.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-7.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-8.png -------------------------------------------------------------------------------- /labs/resources/django.txt: -------------------------------------------------------------------------------- 1 | wget https://www.djangoproject.com/download/1.5.1/tarball/ 2 | tar xzvf Django-1.5.1.tar.gz 3 | cd Django-1.5.1 4 | sudo python setup.py install -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-1st-class-2-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-1st-class-2-1.jpg -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-1st-class-2-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-1st-class-2-2.jpg -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-1st-class-3-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-1st-class-3-1.jpg -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-1st-class-3-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-1st-class-3-2.jpg -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-2nd-class-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-2nd-class-3-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-2nd-class-3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-2nd-class-3-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-2-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-2-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-2-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-2-3.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-2-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-2-4.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-2-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-2-5.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-3-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-3-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-4th-class-3-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-4th-class-3-3.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-1-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-1-1.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-1-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-1-2.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-1-3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-1-3.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-1-4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-1-4.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-1.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-2.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-3.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-4.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-5.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-6.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-7.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-8.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-2-9.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-2-9.PNG -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-3-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-3-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-5th-class-3-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-5th-class-3-3.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-1-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-1-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-1-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-1-3.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-1-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-1-4.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-3.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-4.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-5.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-6.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-7.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-6th-class-2-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-6th-class-2-8.png -------------------------------------------------------------------------------- /labs/solutions/exercise4/exercise4-2.py: -------------------------------------------------------------------------------- 1 | print [(a,b,c) for c in range(1, 11) for b in range(1, c + 1) for a in range(1, b + 1) if a ** 2 + b ** 2 == c ** 2 and a + b + c == 24] -------------------------------------------------------------------------------- /labs/demos/cProfile/profile_sorting.py: -------------------------------------------------------------------------------- 1 | import cProfile 2 | import sorting 3 | import random 4 | l = range(500) 5 | random.shuffle(l) 6 | cProfile.run('sorting.selectionSort(l)') 7 | -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-3-1-300x178.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-3-1-300x178.png -------------------------------------------------------------------------------- /tutorial/images/functional-programming-for-java-developers-reduce.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/functional-programming-for-java-developers-reduce.gif -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-1.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-2.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-3.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-4.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-5.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-6.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-7.png -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-3rd-class-community-documentation-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-3rd-class-community-documentation-8.png -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/polls/templates/polls/detail.html: -------------------------------------------------------------------------------- 1 |

{{ poll.question }}

2 | 7 | -------------------------------------------------------------------------------- /tutorial/images/python-tutorial-the-1st-class-4-unicode-support-basic-input-output-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/PyConTW2013Tutorial/HEAD/tutorial/images/python-tutorial-the-1st-class-4-unicode-support-basic-input-output-1.jpg -------------------------------------------------------------------------------- /labs/solutions/exercise2/hello.py: -------------------------------------------------------------------------------- 1 | # coding=UTF-8 2 | filename = raw_input('檔名:') 3 | f = open(filename, 'r') 4 | b_str = f.read() 5 | f.close() 6 | print b_str.decode('utf-8') # what's this? 7 | print b_str.decode('utf-8').encode('utf-8') # what's this? -------------------------------------------------------------------------------- /labs/solutions/exercise5/main.py: -------------------------------------------------------------------------------- 1 | import pycon.xmath as math 2 | import pycon.bank as bank 3 | 4 | print math.max(10, 5) 5 | print math.sum(1, 2, 3, 4, 5) 6 | print math.pi 7 | 8 | acct = bank.Account('Justin', '123-4567', 1000) 9 | acct.deposit(500) 10 | acct.withdraw(200) 11 | print acct -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/polls/templates/polls/index.html: -------------------------------------------------------------------------------- 1 | {% if latest_poll_list %} 2 | 7 | {% else %} 8 |

No polls are available.

9 | {% endif %} 10 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /labs/solutions/exercise5/pycon/xmath.py: -------------------------------------------------------------------------------- 1 | def max(a, b): 2 | return a if a > b else b 3 | 4 | def min(a, b): 5 | return a if a < b else b 6 | 7 | def sum(*numbers): 8 | total = 0 9 | for number in numbers: 10 | total += number 11 | return total 12 | 13 | pi = 3.141592653589793 14 | e = 2.718281828459045 -------------------------------------------------------------------------------- /labs/solutions/exercise6/main.py: -------------------------------------------------------------------------------- 1 | names = ['Justin', 'caterpillar', 'openhome'] 2 | for i in range(len(names)): 3 | print '{0}, {1}'.format(i, names[i]) 4 | 5 | for i, name in zip(range(len(names)), names): 6 | print '{0}, {1}'.format(i, name) 7 | 8 | for i, name in enumerate(names): 9 | print '{0}, {1}'.format(i, name) -------------------------------------------------------------------------------- /labs/solutions/exercise9/mysite/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/templates/polls/index.html: -------------------------------------------------------------------------------- 1 | {% if latest_poll_list %} 2 | 7 | {% else %} 8 |

No polls are available.

9 | {% endif %} 10 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/templates/polls/results.html: -------------------------------------------------------------------------------- 1 |

{{ poll.question }}

2 | 3 | 8 | 9 | Vote again? 10 | -------------------------------------------------------------------------------- /labs/demos/timeit/sorting.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | repeats = 1000 3 | for f in ('selectionSort', 'insertionSort', 'bubbleSort'): 4 | t = timeit.Timer('{0}([10, 9, 1, 2, 5, 3, 8, 7])'.format(f), 5 | 'from sorting import selectionSort, insertionSort, bubbleSort') 6 | sec = t.timeit(repeats) / repeats 7 | print '{f}\t{sec:.6f} sec'.format(**locals()) -------------------------------------------------------------------------------- /labs/demos/timeit/timeit_sorting.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | repeats = 1000 3 | for f in ('selectionSort', 'insertionSort', 'bubbleSort'): 4 | t = timeit.Timer('{0}([10, 9, 1, 2, 5, 3, 8, 7])'.format(f), 5 | 'from sorting import selectionSort, insertionSort, bubbleSort') 6 | sec = t.timeit(repeats) / repeats 7 | print '{f}\t{sec:.6f} sec'.format(**locals()) -------------------------------------------------------------------------------- /labs/solutions/exercise14/util_test.txt: -------------------------------------------------------------------------------- 1 | The ``util`` module 2 | ====================== 3 | 4 | Using ``sorted`` 5 | ------------------- 6 | 7 | >>> from util import * 8 | >>> sorted([2, 1, 3, 6, 5]) 9 | [1, 2, 3, 5, 6] 10 | >>> sorted([2, 1, 3, 6, 5], ascending) 11 | [1, 2, 3, 5, 6] 12 | >>> sorted([2, 1, 3, 6, 5], descending) 13 | [6, 5, 3, 2, 1] 14 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: a - b) 15 | [1, 2, 3, 5, 6] 16 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: b - a) 17 | [6, 5, 3, 2, 1] -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/polls/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file demonstrates writing tests using the unittest module. These will pass 3 | when you run "manage.py test". 4 | 5 | Replace this with more appropriate tests for your application. 6 | """ 7 | 8 | from django.test import TestCase 9 | 10 | 11 | class SimpleTest(TestCase): 12 | def test_basic_addition(self): 13 | """ 14 | Tests that 1 + 1 always equals 2. 15 | """ 16 | self.assertEqual(1 + 1, 2) 17 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/polls/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file demonstrates writing tests using the unittest module. These will pass 3 | when you run "manage.py test". 4 | 5 | Replace this with more appropriate tests for your application. 6 | """ 7 | 8 | from django.test import TestCase 9 | 10 | 11 | class SimpleTest(TestCase): 12 | def test_basic_addition(self): 13 | """ 14 | Tests that 1 + 1 always equals 2. 15 | """ 16 | self.assertEqual(1 + 1, 2) 17 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/polls/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file demonstrates writing tests using the unittest module. These will pass 3 | when you run "manage.py test". 4 | 5 | Replace this with more appropriate tests for your application. 6 | """ 7 | 8 | from django.test import TestCase 9 | 10 | 11 | class SimpleTest(TestCase): 12 | def test_basic_addition(self): 13 | """ 14 | Tests that 1 + 1 always equals 2. 15 | """ 16 | self.assertEqual(1 + 1, 2) 17 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file demonstrates writing tests using the unittest module. These will pass 3 | when you run "manage.py test". 4 | 5 | Replace this with more appropriate tests for your application. 6 | """ 7 | 8 | from django.test import TestCase 9 | 10 | 11 | class SimpleTest(TestCase): 12 | def test_basic_addition(self): 13 | """ 14 | Tests that 1 + 1 always equals 2. 15 | """ 16 | self.assertEqual(1 + 1, 2) 17 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | 3 | from polls import views 4 | 5 | urlpatterns = patterns('', 6 | # ex: /polls/ 7 | url(r'^$', views.index, name='index'), 8 | # ex: /polls/5/ 9 | url(r'^(?P\d+)/$', views.detail, name='detail'), 10 | # ex: /polls/5/results/ 11 | url(r'^(?P\d+)/results/$', views.results, name='results'), 12 | # ex: /polls/5/vote/ 13 | url(r'^(?P\d+)/vote/$', views.vote, name='vote'), 14 | ) 15 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | 3 | from polls import views 4 | 5 | urlpatterns = patterns('', 6 | # ex: /polls/ 7 | url(r'^$', views.index, name='index'), 8 | # ex: /polls/5/ 9 | url(r'^(?P\d+)/$', views.detail, name='detail'), 10 | # ex: /polls/5/results/ 11 | url(r'^(?P\d+)/results/$', views.results, name='results'), 12 | # ex: /polls/5/vote/ 13 | url(r'^(?P\d+)/vote/$', views.vote, name='vote'), 14 | ) 15 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, url 2 | 3 | from polls import views 4 | 5 | urlpatterns = patterns('', 6 | # ex: /polls/ 7 | url(r'^$', views.index, name='index'), 8 | # ex: /polls/5/ 9 | url(r'^(?P\d+)/$', views.detail, name='detail'), 10 | # ex: /polls/5/results/ 11 | url(r'^(?P\d+)/results/$', views.results, name='results'), 12 | # ex: /polls/5/vote/ 13 | url(r'^(?P\d+)/vote/$', views.vote, name='vote'), 14 | ) 15 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/polls/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | def index(request): 4 | return HttpResponse("Hello, world. You're at the poll index.") 5 | 6 | def detail(request, poll_id): 7 | return HttpResponse("You're looking at poll {id}.".format(id = poll_id)) 8 | 9 | def results(request, poll_id): 10 | return HttpResponse("You're looking at the results of poll {id}.".format(id = poll_id)) 11 | 12 | def vote(request, poll_id): 13 | return HttpResponse("You're voting on poll {id}.".format(id = poll_id)) 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/templates/polls/detail.html: -------------------------------------------------------------------------------- 1 |

{{ poll.question }}

2 | 3 | {% if error_message %}

{{ error_message }}

{% endif %} 4 | 5 |
6 | {% csrf_token %} 7 | 8 | {% for choice in poll.choice_set.all %} 9 | 10 |
11 | {% endfor %} 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /labs/exercises/exercise14/util.py: -------------------------------------------------------------------------------- 1 | def ascending(a, b): return a - b 2 | def descending(a, b): return -ascending(a, b) 3 | # selection sort 4 | def sorted(xs, compare = ascending): 5 | return [] if not xs else __select(xs, compare) 6 | 7 | def __select(xs, compare): 8 | selected = reduce( 9 | lambda slt, elem: elem if compare(elem, slt) < 0 else slt, xs) 10 | remain = [elem for elem in xs if elem != selected] 11 | return (xs if not remain 12 | else [elem for elem in xs if elem == selected] 13 | + __select(remain, compare)) 14 | 15 | print sorted([2, 1, 3, 6, 5]) 16 | print sorted([2, 1, 3, 6, 5], descending) -------------------------------------------------------------------------------- /labs/solutions/exercise7/main.py: -------------------------------------------------------------------------------- 1 | def ascending(a, b): return a - b 2 | def descending(a, b): return -ascending(a, b) 3 | # selection sort 4 | def sorted(xs, compare = ascending): 5 | return [] if not xs else __select(xs, compare) 6 | 7 | def __select(xs, compare): 8 | selected = reduce( 9 | lambda slt, elem: elem if compare(elem, slt) < 0 else slt, xs) 10 | remain = [elem for elem in xs if elem != selected] 11 | return (xs if not remain 12 | else [elem for elem in xs if elem == selected] 13 | + __select(remain, compare)) 14 | 15 | print sorted([2, 1, 3, 6, 5]) 16 | print sorted([2, 1, 3, 6, 5], descending) -------------------------------------------------------------------------------- /labs/solutions/exercise9/mysite/mysite/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Examples: 9 | # url(r'^$', 'mysite.views.home', name='home'), 10 | # url(r'^mysite/', include('mysite.foo.urls')), 11 | 12 | # Uncomment the admin/doc line below to enable admin documentation: 13 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | # url(r'^admin/', include(admin.site.urls)), 17 | ) 18 | -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/mysite/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | # Examples: 9 | # url(r'^$', 'mysite.views.home', name='home'), 10 | # url(r'^mysite/', include('mysite.foo.urls')), 11 | 12 | # Uncomment the admin/doc line below to enable admin documentation: 13 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | # url(r'^admin/', include(admin.site.urls)), 17 | ) 18 | -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Poll(models.Model): 4 | question = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __unicode__(self): 11 | return self.question 12 | 13 | class Choice(models.Model): 14 | poll = models.ForeignKey(Poll) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField() 17 | 18 | def __unicode__(self): 19 | return self.choice_text 20 | 21 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Poll(models.Model): 4 | question = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __unicode__(self): 11 | return self.question 12 | 13 | class Choice(models.Model): 14 | poll = models.ForeignKey(Poll) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField() 17 | 18 | def __unicode__(self): 19 | return self.choice_text 20 | 21 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Poll(models.Model): 4 | question = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __unicode__(self): 11 | return self.question 12 | 13 | class Choice(models.Model): 14 | poll = models.ForeignKey(Poll) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField() 17 | 18 | def __unicode__(self): 19 | return self.choice_text 20 | 21 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Poll(models.Model): 4 | question = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __unicode__(self): 11 | return self.question 12 | 13 | class Choice(models.Model): 14 | poll = models.ForeignKey(Poll) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField() 17 | 18 | def __unicode__(self): 19 | return self.choice_text 20 | 21 | -------------------------------------------------------------------------------- /labs/solutions/exercise5/pycon/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name, number, balance): 3 | self.name = name 4 | self.number = number 5 | self.balance = balance 6 | 7 | def deposit(self, amount): 8 | if amount <= 0: 9 | raise ValueError('amount must be positive') 10 | self.balance += amount 11 | 12 | def withdraw(self, amount): 13 | if amount > self.balance: 14 | raise RuntimeError('balance not enough') 15 | self.balance -= amount 16 | 17 | def __str__(self): 18 | return 'Account({0}, {1}, {2})'.format( 19 | self.name, self.number, self.balance) 20 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/mysite/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | url(r'^polls/', include('polls.urls')) 9 | # Examples: 10 | # url(r'^$', 'mysite.views.home', name='home'), 11 | # url(r'^mysite/', include('mysite.foo.urls')), 12 | 13 | # Uncomment the admin/doc line below to enable admin documentation: 14 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 15 | 16 | # Uncomment the next line to enable the admin: 17 | # url(r'^admin/', include(admin.site.urls)), 18 | ) 19 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/mysite/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | url(r'^polls/', include('polls.urls')) 9 | # Examples: 10 | # url(r'^$', 'mysite.views.home', name='home'), 11 | # url(r'^mysite/', include('mysite.foo.urls')), 12 | 13 | # Uncomment the admin/doc line below to enable admin documentation: 14 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 15 | 16 | # Uncomment the next line to enable the admin: 17 | # url(r'^admin/', include(admin.site.urls)), 18 | ) 19 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/mysite/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | # Uncomment the next two lines to enable the admin: 4 | # from django.contrib import admin 5 | # admin.autodiscover() 6 | 7 | urlpatterns = patterns('', 8 | url(r'^polls/', include('polls.urls', namespace='polls')) 9 | # Examples: 10 | # url(r'^$', 'mysite.views.home', name='home'), 11 | # url(r'^mysite/', include('mysite.foo.urls')), 12 | 13 | # Uncomment the admin/doc line below to enable admin documentation: 14 | # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 15 | 16 | # Uncomment the next line to enable the admin: 17 | # url(r'^admin/', include(admin.site.urls)), 18 | ) 19 | -------------------------------------------------------------------------------- /labs/exercises/exercise7/main.py: -------------------------------------------------------------------------------- 1 | def ascending(a, b): return a - b 2 | def descending(a, b): return -ascending(a, b) 3 | # selection sort 4 | def sorted(xs, compare = ascending): 5 | return [] if not xs else __select(xs, compare) 6 | 7 | def __select(xs, compare): 8 | selected = xs[0] 9 | for elem in xs[1:]: 10 | if compare(elem, selected) < 0: 11 | selected = elem 12 | 13 | remain = [] 14 | selected_list = [] 15 | for elem in xs: 16 | if elem != selected: 17 | remain.append(elem) 18 | else: 19 | selected_list.append(elem) 20 | 21 | return xs if not remain else selected_list + __select(remain, compare) 22 | 23 | print sorted([2, 1, 3, 6, 5]) 24 | print sorted([2, 1, 3, 6, 5], descending) -------------------------------------------------------------------------------- /labs/exercises/exercise4/exercise4-2.py: -------------------------------------------------------------------------------- 1 | # First, let's try generating all triangles with sides equal to or smaller than 10. 2 | # print [(a,b,c) for c in range(1, 11) for b in range(1, 11) for a in range(1, 11)] 3 | 4 | # Next, we'll add a condition that they all have to be right triangles. We'll also modify this function by taking into consideration that side b isn't larger than the hypothenuse and that side a isn't larger than side b. 5 | # print [(a,b,c) for c in range(1, 11) for b in range(1, c + 1) for a in range(1, b + 1) if a ** 2 + b ** 2 == c ** 2] 6 | 7 | # Finally, we just modify the function by saying that we want the ones where the perimeter is 24. 8 | # print [(a,b,c) for c in range(1, 11) for b in range(1, c + 1) for a in range(1, b + 1) if a ** 2 + b ** 2 == c ** 2 and a + b + c == 24] -------------------------------------------------------------------------------- /labs/exercises/exercise15/test_dvdlib.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from dvdlib import Customer, Movie, Rental 3 | 4 | class CustomerTestCase(unittest.TestCase): 5 | def setUp(self): 6 | self.customer = Customer('test') 7 | movies = [Movie('ABC', Movie.NEW_RELEASE), Movie('XYZ', Movie.REGULAR), Movie('123', Movie.CHILDRENS)] 8 | for movie in movies: 9 | self.customer.add_rental(Rental(movie, 7)) 10 | 11 | def test_statement(self): 12 | statement = self.customer.statement() 13 | self.assertTrue( 14 | 'ABC 21' in statement and 15 | 'XYZ 9.5' in statement and 16 | '123 7.5' in statement and 17 | 'Amount owed is 38.0' in statement and 18 | 'You earned 4 frequent renter points' in statement 19 | ) 20 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/polls/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | from polls.models import Poll 4 | from django.http import Http404 5 | 6 | def index(request): 7 | latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] 8 | context = {'latest_poll_list': latest_poll_list} 9 | return render(request, 'polls/index.html', context) 10 | 11 | def detail(request, poll_id): 12 | try: 13 | poll = Poll.objects.get(pk=poll_id) 14 | except Poll.DoesNotExist: 15 | raise Http404 16 | return render(request, 'polls/detail.html', {'poll': poll}) 17 | 18 | def results(request, poll_id): 19 | return HttpResponse("You're looking at the results of poll {id}.".format(id = poll_id)) 20 | 21 | def vote(request, poll_id): 22 | return HttpResponse("You're voting on poll {id}.".format(id = poll_id)) 23 | -------------------------------------------------------------------------------- /labs/exercises/exercise5/main.py: -------------------------------------------------------------------------------- 1 | def max(a, b): 2 | return a if a > b else b 3 | 4 | def min(a, b): 5 | return a if a < b else b 6 | 7 | def sum(*numbers): 8 | total = 0 9 | for number in numbers: 10 | total += number 11 | return total 12 | 13 | pi = 3.141592653589793 14 | e = 2.718281828459045 15 | 16 | def account(name, number, balance): 17 | return {'name': name, 'number': number, 'balance': balance} 18 | 19 | def deposit(acct, amount): 20 | if amount <= 0: 21 | raise ValueError('amount must be positive') 22 | acct['balance'] += amount 23 | 24 | def withdraw(acct, amount): 25 | if amount > acct['balance']: 26 | raise RuntimeError('balance not enough') 27 | acct['balance'] -= amount 28 | 29 | def to_str(acct): 30 | return 'Account:' + str(acct) 31 | 32 | print max(10, 5) 33 | print sum(1, 2, 3, 4, 5) 34 | print pi 35 | 36 | acct = account('Justin', '123-4567', 1000) 37 | deposit(acct, 500) 38 | withdraw(acct, 200) 39 | print to_str(acct) -------------------------------------------------------------------------------- /labs/solutions/exercise15/test_dvdlib.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from dvdlib import Customer, Movie, Rental 3 | 4 | class CustomerTestCase(unittest.TestCase): 5 | def setUp(self): 6 | self.customer = Customer('test') 7 | movies = [Movie('ABC', Movie.NEW_RELEASE), Movie('XYZ', Movie.REGULAR), Movie('123', Movie.CHILDRENS)] 8 | for movie in movies: 9 | self.customer.add_rental(Rental(movie, 7)) 10 | 11 | def test_statement(self): 12 | statement = self.customer.statement() 13 | self.assertTrue( 14 | 'ABC 21' in statement and 15 | 'XYZ 9.5' in statement and 16 | '123 7.5' in statement and 17 | 'Amount owed is 38.0' in statement and 18 | 'You earned 4 frequent renter points' in statement 19 | ) 20 | 21 | def test_get_total_charge(self): 22 | total = self.customer.get_total_charge() 23 | self.assertEquals(38.0, total) 24 | 25 | def test_get_total_freq_renter_points(self): 26 | total_freq_renter_points = self.customer.get_total_freq_renter_points() 27 | self.assertEquals(4, total_freq_renter_points) 28 | -------------------------------------------------------------------------------- /labs/demos/timeit/sorting-Justin-2012.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | 3 | def ascending(a, b): return a - b 4 | def descending(a, b): return -ascending(a, b) 5 | 6 | def selectionSort(xs, compare = ascending): 7 | return [] if not xs else __select(xs, compare) 8 | 9 | def __select(xs, compare): 10 | selected = reduce( 11 | lambda m, k: m if compare(m, k) < 0 else k, xs) 12 | remain = [elem for elem in xs if elem != selected] 13 | return (xs if not remain 14 | else [elem for elem in xs if elem == selected] 15 | + __select(remain, compare)) 16 | 17 | def insertionSort(xs, compare = ascending): 18 | return ([] if not xs 19 | else __insert(xs[0], 20 | insertionSort(xs[1:], compare), compare)) 21 | 22 | def __insert(x, xs, compare): 23 | return ([x] + xs if not xs or compare(x, xs[0]) <= 0 24 | else [xs[0]] + __insert(x, xs[1:], compare)) 25 | 26 | def bubbleSort(xs, compare = ascending): 27 | return [] if not xs else __up(xs, compare) 28 | 29 | def __up(xs, compare): 30 | if not xs[1:]: 31 | return xs 32 | else: 33 | s = bubbleSort(xs[1:], compare) 34 | return ([s[0]] + __up([xs[0]] + s[1:], compare) 35 | if compare(xs[0], s[0]) > 0 36 | else [xs[0]] + s) 37 | -------------------------------------------------------------------------------- /labs/solutions/exercise14/util.py: -------------------------------------------------------------------------------- 1 | def ascending(a, b): return a - b 2 | def descending(a, b): return -ascending(a, b) 3 | # selection sort 4 | def sorted(xs, compare = ascending): 5 | ''' 6 | sorted(xs) -> new sorted list from xs' item in ascending order. 7 | sorted(xs, func) -> new sorted list. func should return a negative integer, 8 | zero, or a positive integer as the first argument is 9 | less than, equal to, or greater than the second. 10 | 11 | >>> sorted([2, 1, 3, 6, 5]) 12 | [1, 2, 3, 5, 6] 13 | >>> sorted([2, 1, 3, 6, 5], ascending) 14 | [1, 2, 3, 5, 6] 15 | >>> sorted([2, 1, 3, 6, 5], descending) 16 | [6, 5, 3, 2, 1] 17 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: a - b) 18 | [1, 2, 3, 5, 6] 19 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: b - a) 20 | [6, 5, 3, 2, 1] 21 | ''' 22 | 23 | return [] if not xs else __select(xs, compare) 24 | 25 | def __select(xs, compare): 26 | selected = reduce( 27 | lambda slt, elem: elem if compare(elem, slt) < 0 else slt, xs) 28 | remain = [elem for elem in xs if elem != selected] 29 | return (xs if not remain 30 | else [elem for elem in xs if elem == selected] 31 | + __select(remain, compare)) 32 | 33 | if __name__ == '__main__': 34 | import doctest 35 | doctest.testmod() 36 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/polls/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import get_object_or_404, render 2 | from django.core.urlresolvers import reverse 3 | from django.http import Http404, HttpResponseRedirect 4 | from polls.models import Poll, Choice 5 | 6 | def index(request): 7 | latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] 8 | context = {'latest_poll_list': latest_poll_list} 9 | return render(request, 'polls/index.html', context) 10 | 11 | def detail(request, poll_id): 12 | try: 13 | poll = Poll.objects.get(pk=poll_id) 14 | except Poll.DoesNotExist: 15 | raise Http404 16 | return render(request, 'polls/detail.html', {'poll': poll}) 17 | 18 | def results(request, poll_id): 19 | poll = get_object_or_404(Poll, pk=poll_id) 20 | return render(request, 'polls/results.html', {'poll': poll}) 21 | 22 | def vote(request, poll_id): 23 | p = get_object_or_404(Poll, pk=poll_id) 24 | try: 25 | selected_choice = p.choice_set.get(pk=request.POST['choice']) 26 | except (KeyError, Choice.DoesNotExist): 27 | return render(request, 'polls/detail.html', { 28 | 'poll': p, 29 | 'error_message': "You didn't select a choice.", 30 | }) 31 | else: 32 | selected_choice.votes += 1 33 | selected_choice.save() 34 | return HttpResponseRedirect(reverse('polls:results', args=(p.id,))) 35 | -------------------------------------------------------------------------------- /labs/demos/cProfile/sorting.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | 3 | def ascending(a, b): return a - b 4 | def descending(a, b): return -ascending(a, b) 5 | 6 | def selectionSort(xs, compare = ascending): 7 | return [] if not xs else __select(xs, compare) 8 | 9 | def __select(xs, compare): 10 | selected = reduce( 11 | lambda m, k: m if compare(m, k) < 0 else k, xs) 12 | remain = [elem for elem in xs if elem != selected] 13 | return (xs if not remain 14 | else [elem for elem in xs if elem == selected] 15 | + __select(remain, compare)) 16 | 17 | def insertionSort(xs, compare = ascending): 18 | return ([] if not xs 19 | else __insert(xs[0], 20 | insertionSort(xs[1:], compare), compare)) 21 | 22 | def __insert(x, xs, compare): 23 | return ([x] + xs if not xs or compare(x, xs[0]) <= 0 24 | else [xs[0]] + __insert(x, xs[1:], compare)) 25 | 26 | def bubbleSort(xs, compare = ascending): 27 | return [] if not xs else __up(xs, compare) 28 | 29 | def __up(xs, compare): 30 | if not xs[1:]: 31 | return xs 32 | else: 33 | s = bubbleSort(xs[1:], compare) 34 | return ([s[0]] + __up([xs[0]] + s[1:], compare) 35 | if compare(xs[0], s[0]) > 0 36 | else [xs[0]] + s) 37 | 38 | if __name__ == '__main__': 39 | import random 40 | l = range(500) 41 | random.shuffle(l) 42 | assert range(500) == selectionSort(l) 43 | -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks 19 | # if running multiple sites in the same mod_wsgi process. To fix this, use 20 | # mod_wsgi daemon mode with each site in its own daemon process, or use 21 | # os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings" 22 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 23 | 24 | # This application object is used by any WSGI server configured to use this 25 | # file. This includes Django's development server, if the WSGI_APPLICATION 26 | # setting points here. 27 | from django.core.wsgi import get_wsgi_application 28 | application = get_wsgi_application() 29 | 30 | # Apply WSGI middleware here. 31 | # from helloworld.wsgi import HelloWorldApplication 32 | # application = HelloWorldApplication(application) 33 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks 19 | # if running multiple sites in the same mod_wsgi process. To fix this, use 20 | # mod_wsgi daemon mode with each site in its own daemon process, or use 21 | # os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings" 22 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 23 | 24 | # This application object is used by any WSGI server configured to use this 25 | # file. This includes Django's development server, if the WSGI_APPLICATION 26 | # setting points here. 27 | from django.core.wsgi import get_wsgi_application 28 | application = get_wsgi_application() 29 | 30 | # Apply WSGI middleware here. 31 | # from helloworld.wsgi import HelloWorldApplication 32 | # application = HelloWorldApplication(application) 33 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks 19 | # if running multiple sites in the same mod_wsgi process. To fix this, use 20 | # mod_wsgi daemon mode with each site in its own daemon process, or use 21 | # os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings" 22 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 23 | 24 | # This application object is used by any WSGI server configured to use this 25 | # file. This includes Django's development server, if the WSGI_APPLICATION 26 | # setting points here. 27 | from django.core.wsgi import get_wsgi_application 28 | application = get_wsgi_application() 29 | 30 | # Apply WSGI middleware here. 31 | # from helloworld.wsgi import HelloWorldApplication 32 | # application = HelloWorldApplication(application) 33 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks 19 | # if running multiple sites in the same mod_wsgi process. To fix this, use 20 | # mod_wsgi daemon mode with each site in its own daemon process, or use 21 | # os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings" 22 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 23 | 24 | # This application object is used by any WSGI server configured to use this 25 | # file. This includes Django's development server, if the WSGI_APPLICATION 26 | # setting points here. 27 | from django.core.wsgi import get_wsgi_application 28 | application = get_wsgi_application() 29 | 30 | # Apply WSGI middleware here. 31 | # from helloworld.wsgi import HelloWorldApplication 32 | # application = HelloWorldApplication(application) 33 | -------------------------------------------------------------------------------- /labs/solutions/exercise9/mysite/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks 19 | # if running multiple sites in the same mod_wsgi process. To fix this, use 20 | # mod_wsgi daemon mode with each site in its own daemon process, or use 21 | # os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings" 22 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") 23 | 24 | # This application object is used by any WSGI server configured to use this 25 | # file. This includes Django's development server, if the WSGI_APPLICATION 26 | # setting points here. 27 | from django.core.wsgi import get_wsgi_application 28 | application = get_wsgi_application() 29 | 30 | # Apply WSGI middleware here. 31 | # from helloworld.wsgi import HelloWorldApplication 32 | # application = HelloWorldApplication(application) 33 | -------------------------------------------------------------------------------- /labs/exercises/exercise8/pickle/models.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | 3 | class DVD: 4 | def __init__(self, title, year=None, duration=None, director_id=None): 5 | self.title = title 6 | self.year = year 7 | self.duration = duration 8 | self.director_id = director_id 9 | self.filename = self.title.replace(' ', '_') + '.pkl' 10 | 11 | def check_filename(self, filename): 12 | if filename is not None: 13 | self.filename = filename 14 | 15 | def save(self, filename=None): 16 | self.check_filename(filename) 17 | 18 | fh = None 19 | try: 20 | # todo.. 21 | 22 | 23 | except (EnvironmentError, pickle.PicklingError) as err: 24 | raise SaveError(str(err)) 25 | finally: 26 | if fh is not None: 27 | fh.close() 28 | 29 | def load(self, filename=None): 30 | self.check_filename(filename) 31 | 32 | fh = None 33 | try: 34 | # todo.. 35 | 36 | 37 | except (EnvironmentError, pickle.PicklingError) as err: 38 | raise LoadError(str(err)) 39 | finally: 40 | if fh is not None: 41 | fh.close() 42 | 43 | def __str__(self): 44 | return 'DVD({0}, {1}, {2}, {3})'.format( 45 | self.title, self.year, self.duration, self.director_id) 46 | 47 | def main(): 48 | filename = 'PyConTutorial2013.pkl' 49 | dvd1 = DVD('PyCon Tutorial', 2013, 1, 'Justin Lin') 50 | dvd1.save() 51 | dvd2 = DVD('PyCon Tutorial') 52 | dvd2.load() 53 | print dvd2 54 | 55 | 56 | if __name__ == '__main__': 57 | main() -------------------------------------------------------------------------------- /schedule.txt: -------------------------------------------------------------------------------- 1 | PyCon Taiwan 2013 Tutorial 2 | 3 | Justin Lin 4 | 5 | Type:Tutorial 6 | Audience level:Novice 7 | Category:Core Python and Ecosystem (Language, Libraries, Culture) 8 | (May 24th 09:00 – 17:00) 9 | 10 | Description 11 | 12 | Understanding cultures and ecosystem of a language takes me about three to six months. This six-hour course wraps up what I - an experienced Java developer - have learned from Python ecosystem and the agenda of the past PyConTW. 13 | 14 | Abstract 15 | 16 | The tutorial works like this: There's a short presentation. A short lab for you to complete. Rinse/repeat until we run out of time. Hopefully you'll walk away from this tutorial knowing the core and ecosystem of Python. 17 | 18 | Course will cover: 19 | 20 | Picking and installing an Interpreter 21 | Introduction to Unicode support 22 | Basic Input and Output 23 | Built-in Types 24 | if, for, while and for Comprehensions 25 | Functions, Modules, Classes and Packages 26 | The Community 27 | Documentation 28 | Data Management Functions 29 | Object serialization 30 | Database 31 | Django 32 | Test 33 | ... 34 | 35 | There are short labs to allow participants to practice concepts. 36 | 37 | ================================================================= 38 | 39 | PyCon Taiwan 2013 入門課程 40 | 41 | 林信良 42 | 43 | 課程種類:入門 44 | 學員程度:初學者 45 | 課程分類:Python 核心與生態(語言、程式庫與文化) 46 | 5 月 24 日 09:00 – 17:00 47 | 48 | 說明: 49 | 50 | 以我來說,瞭解一個語言的文化與生態大概要花三到六個月的時間。作為一個熟知Java領域的開發者,這六個小時的入門課程,將呈現我至今對Python生態與過去PythonConTW議程的瞭解過程與心得。 51 | 52 | 進行方式: 53 | 54 | 透過投影片進行簡要說明與介紹,而後進行實作,以此模式不斷進行直到課程結束。希望學員在課程結束之後,能對Python的核心文化與生態能有所瞭解。 55 | 56 | 涵蓋內容: 57 | 58 | Python版本的選擇與安裝 59 | 簡介Unicode支援 60 | 基本輸入輸出 61 | 內建型態 62 | if、for、while與for Comprehensions 63 | 函數、模組、類別與套件 64 | 社群 65 | 文件 66 | 資料處理函式 67 | 物件序列化 68 | 資料庫程式 69 | Django 70 | 測試 71 | ... 72 | 73 | 課程穿插頻繁實作,讓學員從實作中驗證觀念。 74 | 75 | -------------------------------------------------------------------------------- /labs/solutions/exercise8/pickle/models.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | 3 | class DVD: 4 | def __init__(self, title, year=None, duration=None, director_id=None): 5 | self.title = title 6 | self.year = year 7 | self.duration = duration 8 | self.director_id = director_id 9 | self.filename = self.title.replace(' ', '_') + '.pkl' 10 | 11 | def check_filename(self, filename): 12 | if filename is not None: 13 | self.filename = filename 14 | 15 | def save(self, filename=None): 16 | self.check_filename(filename) 17 | 18 | fh = None 19 | try: 20 | data = (self.title, self.year, self.duration, self.director_id) 21 | fh = open(self.filename, 'wb') 22 | pickle.dump(data, fh) 23 | except (EnvironmentError, pickle.PicklingError) as err: 24 | raise SaveError(str(err)) 25 | finally: 26 | if fh is not None: 27 | fh.close() 28 | 29 | def load(self, filename=None): 30 | self.check_filename(filename) 31 | 32 | fh = None 33 | try: 34 | fh = open(self.filename, 'rb') 35 | data = pickle.load(fh) 36 | (self.title, self.year, self.duration, self.director_id) = data 37 | except (EnvironmentError, pickle.PicklingError) as err: 38 | raise LoadError(str(err)) 39 | finally: 40 | if fh is not None: 41 | fh.close() 42 | 43 | def __str__(self): 44 | return 'DVD({0}, {1}, {2}, {3})'.format( 45 | self.title, self.year, self.duration, self.director_id) 46 | 47 | def main(): 48 | filename = 'PyConTutorial2013.pkl' 49 | dvd1 = DVD('PyCon Tutorial', 2013, 1, 'Justin Lin') 50 | dvd1.save() 51 | dvd2 = DVD('PyCon Tutorial') 52 | dvd2.load() 53 | print dvd2 54 | 55 | 56 | if __name__ == '__main__': 57 | main() -------------------------------------------------------------------------------- /labs/exercises/exercise8/shelve/models.py: -------------------------------------------------------------------------------- 1 | import shelve 2 | 3 | class DVD: 4 | def __init__(self, title, year=None, duration=None, director_id=None): 5 | self.title = title 6 | self.year = year 7 | self.duration = duration 8 | self.director_id = director_id 9 | 10 | def __str__(self): 11 | return repr(self) 12 | 13 | def __repr__(self): 14 | return 'DVD({0}, {1}, {2}, {3})'.format( 15 | self.title, self.year, self.duration, self.director_id) 16 | 17 | class DvdDao: 18 | def __init__(self, shelve_name): 19 | self.shelve_name = shelve_name 20 | 21 | def save(self, dvd): 22 | shelve_db = None 23 | try: 24 | # todo.. 25 | 26 | 27 | finally: 28 | if shelve_db is not None: 29 | shelve_db.close() 30 | 31 | def all(self): 32 | shelve_db = None 33 | try: 34 | # todo.. 35 | 36 | 37 | finally: 38 | if shelve_db is not None: 39 | shelve_db.close() 40 | return [] 41 | 42 | def load(self, title): 43 | shelve_db = None 44 | try: 45 | # todo.. 46 | 47 | 48 | finally: 49 | if shelve_db is not None: 50 | shelve_db.close() 51 | return None 52 | 53 | def remove(self, title): 54 | shelve_db = None 55 | try: 56 | # todo.. 57 | 58 | 59 | finally: 60 | if shelve_db is not None: 61 | shelve_db.close() 62 | 63 | def main(): 64 | filename = 'dvd_library.slv' 65 | dao = DvdDao(filename) 66 | dvd1 = DVD('PyCon Tutorial 2012', 2012, 1, 'Justin Lin') 67 | dvd2 = DVD('PyCon Tutorial 2013', 2013, 1, 'Justin Lin') 68 | dao.save(dvd1) 69 | dao.save(dvd2) 70 | print dao.all() 71 | print dao.load('PyCon Tutorial 2012') 72 | dao.remove('PyCon Tutorial 2013') 73 | print dao.all() 74 | 75 | if __name__ == '__main__': 76 | main() -------------------------------------------------------------------------------- /labs/exercises/exercise8/sql/dvds.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sqlite3 3 | 4 | def connect(name): 5 | create = not os.path.exists(name) 6 | conn = sqlite3.connect(name) 7 | if create: 8 | sql_directors = ("CREATE TABLE directors (" 9 | "id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, " 10 | "name TEXT UNIQUE NOT NULL)") 11 | sql_dvds = ("CREATE TABLE dvds (" 12 | "id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, " 13 | "title TEXT NOT NULL, " 14 | "year INTEGER NOT NULL, " 15 | "duration INTEGER NOT NULL, " 16 | "director_id INTEGER NOT NULL, " 17 | "FOREIGN KEY (director_id) REFERENCES directors)") 18 | 19 | # todo... 20 | 21 | return conn 22 | 23 | def add_dvd(conn, title, year, duration, director): 24 | director_id = get_and_set_director(conn, director) 25 | sql = ("INSERT INTO dvds " 26 | "(title, year, duration, director_id) " 27 | "VALUES (?, ?, ?, ?)") 28 | # todo... 29 | 30 | def get_and_set_director(conn, director): 31 | director_id = get_director_id(conn, director) 32 | if director_id is not None: 33 | return director_id 34 | cursor = conn.cursor() 35 | cursor.execute("INSERT INTO directors (name) VALUES (?)", 36 | (director,)) 37 | conn.commit() 38 | return get_director_id(conn, director) 39 | 40 | def get_director_id(conn, director): 41 | sql = "SELECT id FROM directors WHERE name=?" 42 | # todo... 43 | 44 | def all_dvds(conn): 45 | sql = ("SELECT dvds.title, dvds.year, dvds.duration, " 46 | "directors.name FROM dvds, directors " 47 | "WHERE dvds.director_id = directors.id" 48 | " ORDER BY dvds.title") 49 | # todo... 50 | 51 | def all_directors(conn): 52 | sql = "SELECT name FROM directors ORDER BY name" 53 | # todo... 54 | 55 | 56 | def main(): 57 | db_name = 'dvd_library.sqlite3' 58 | conn = connect(db_name) 59 | add_dvd(conn, 'Python Tutorial 2013', 2013, 1, 'Justin') 60 | print all_directors(conn) 61 | print all_dvds(conn) 62 | 63 | if __name__ == '__main__': 64 | main() -------------------------------------------------------------------------------- /labs/solutions/exercise8/shelve/models.py: -------------------------------------------------------------------------------- 1 | import shelve 2 | 3 | class DVD: 4 | def __init__(self, title, year=None, duration=None, director_id=None): 5 | self.title = title 6 | self.year = year 7 | self.duration = duration 8 | self.director_id = director_id 9 | 10 | def __str__(self): 11 | return repr(self) 12 | 13 | def __repr__(self): 14 | return 'DVD({0}, {1}, {2}, {3})'.format( 15 | self.title, self.year, self.duration, self.director_id) 16 | 17 | class DvdDao: 18 | def __init__(self, shelve_name): 19 | self.shelve_name = shelve_name 20 | 21 | def save(self, dvd): 22 | shelve_db = None 23 | try: 24 | shelve_db = shelve.open(self.shelve_name) 25 | shelve_db[dvd.title] = (dvd.year, dvd.duration, dvd.director_id) 26 | shelve_db.sync() 27 | finally: 28 | if shelve_db is not None: 29 | shelve_db.close() 30 | 31 | def all(self): 32 | shelve_db = None 33 | try: 34 | shelve_db = shelve.open(self.shelve_name) 35 | return [DVD(title, *shelve_db[title]) 36 | for title in sorted(shelve_db, key=str.lower)] 37 | finally: 38 | if shelve_db is not None: 39 | shelve_db.close() 40 | return [] 41 | 42 | def load(self, title): 43 | shelve_db = None 44 | try: 45 | shelve_db = shelve.open(self.shelve_name) 46 | if title in shelve_db: 47 | return DVD(title, *shelve_db[title]) 48 | finally: 49 | if shelve_db is not None: 50 | shelve_db.close() 51 | return None 52 | 53 | def remove(self, title): 54 | shelve_db = None 55 | try: 56 | shelve_db = shelve.open(self.shelve_name) 57 | del shelve_db[title] 58 | shelve_db.sync() 59 | finally: 60 | if shelve_db is not None: 61 | shelve_db.close() 62 | 63 | def main(): 64 | filename = 'dvd_library.slv' 65 | dao = DvdDao(filename) 66 | dvd1 = DVD('PyCon Tutorial 2012', 2012, 1, 'Justin Lin') 67 | dvd2 = DVD('PyCon Tutorial 2013', 2013, 1, 'Justin Lin') 68 | dao.save(dvd1) 69 | dao.save(dvd2) 70 | print dao.all() 71 | print dao.load('PyCon Tutorial 2012') 72 | dao.remove('PyCon Tutorial 2013') 73 | print dao.all() 74 | 75 | if __name__ == '__main__': 76 | main() -------------------------------------------------------------------------------- /labs/exercises/exercise15/dvdlib.py: -------------------------------------------------------------------------------- 1 | class Movie: 2 | REGULAR = 0 3 | NEW_RELEASE = 1 4 | CHILDRENS = 2 5 | 6 | def __init__(self, title, price_code): 7 | self.title = title 8 | self.price_code = price_code 9 | 10 | 11 | class Rental: 12 | def __init__(self, movie, days_rented): 13 | self.movie = movie 14 | self.days_rented = days_rented 15 | 16 | 17 | class Customer: 18 | def __init__(self, name): 19 | self.name = name 20 | self.rentals = [] 21 | 22 | def add_rental(self, rental): 23 | self.rentals.append(rental) 24 | 25 | def statement(self): 26 | total_amount = 0 27 | freq_renter_points = 0 28 | result = 'Rental Record for ' + self.name + '\n' 29 | for rental in self.rentals: 30 | this_amount = 0 31 | # determine amounts for each line 32 | price_code = rental.movie.price_code 33 | if price_code == Movie.REGULAR: 34 | this_amount += 2 35 | if rental.days_rented > 2: 36 | this_amount += (rental.days_rented - 2) * 1.5 37 | elif price_code == Movie.NEW_RELEASE: 38 | this_amount += (rental.days_rented * 3) 39 | elif price_code == Movie.CHILDRENS: 40 | this_amount += 1.5 41 | if rental.days_rented > 3: 42 | this_amount += (rental.days_rented - 3) * 1.5 43 | 44 | # add frequent renter points 45 | freq_renter_points += 1 46 | 47 | # add bonus for a two day new release rental 48 | if price_code == Movie.NEW_RELEASE and rental.days_rented > 1: 49 | freq_renter_points += 1 50 | 51 | # show figures for this rental 52 | result += '\t' + rental.movie.title + '\t' + str(this_amount) + '\n' 53 | total_amount += this_amount 54 | 55 | # add footer lines 56 | result += 'Amount owed is ' + str(total_amount) + '\n' 57 | result += 'You earned ' + str(freq_renter_points) + ' frequent renter points' 58 | return result 59 | 60 | if __name__ == '__main__': 61 | customer = Customer('test') 62 | movies = [Movie('ABC', Movie.NEW_RELEASE), Movie('XYZ', Movie.REGULAR), Movie('123', Movie.CHILDRENS)] 63 | for movie in movies: 64 | customer.add_rental(Rental(movie, 7)) 65 | print customer.statement() 66 | 67 | 68 | -------------------------------------------------------------------------------- /labs/solutions/exercise15/dvdlib.py: -------------------------------------------------------------------------------- 1 | class Movie: 2 | REGULAR = 0 3 | NEW_RELEASE = 1 4 | CHILDRENS = 2 5 | 6 | def __init__(self, title, price_code): 7 | self.title = title 8 | self.price_code = price_code 9 | 10 | 11 | class Rental: 12 | def __init__(self, movie, days_rented): 13 | self.movie = movie 14 | self.days_rented = days_rented 15 | 16 | def get_charge(self): 17 | this_amount = 0 18 | price_code = self.movie.price_code 19 | if price_code == Movie.REGULAR: 20 | this_amount += 2 21 | if self.days_rented > 2: 22 | this_amount += (self.days_rented - 2) * 1.5 23 | elif price_code == Movie.NEW_RELEASE: 24 | this_amount += (self.days_rented * 3) 25 | elif price_code == Movie.CHILDRENS: 26 | this_amount += 1.5 27 | if self.days_rented > 3: 28 | this_amount += (self.days_rented - 3) * 1.5 29 | return this_amount 30 | 31 | def get_freq_renter_points(self): 32 | return 2 if self.movie.price_code == Movie.NEW_RELEASE and self.days_rented > 1 else 1 33 | 34 | 35 | class Customer: 36 | def __init__(self, name): 37 | self.name = name 38 | self.rentals = [] 39 | 40 | def add_rental(self, rental): 41 | self.rentals.append(rental) 42 | 43 | def statement(self): 44 | freq_renter_points = 0 45 | result = 'Rental Record for ' + self.name + '\n' 46 | for rental in self.rentals: 47 | result += '\t' + rental.movie.title + '\t' + str(rental.get_charge() ) + '\n' 48 | 49 | result += 'Amount owed is ' + str(self.get_total_charge()) + '\n' 50 | result += 'You earned ' + str(self.get_total_freq_renter_points()) + ' frequent renter points' 51 | return result 52 | 53 | def get_total_charge(self): 54 | total_amount = 0 55 | for rental in self.rentals: 56 | total_amount += rental.get_charge() 57 | return total_amount 58 | 59 | def get_total_freq_renter_points(self): 60 | freq_renter_points = 0 61 | for rental in self.rentals: 62 | freq_renter_points += rental.get_freq_renter_points() 63 | return freq_renter_points 64 | 65 | 66 | if __name__ == '__main__': 67 | customer = Customer('test') 68 | movies = [Movie('ABC', Movie.NEW_RELEASE), Movie('XYZ', Movie.REGULAR), Movie('123', Movie.CHILDRENS)] 69 | for movie in movies: 70 | customer.add_rental(Rental(movie, 7)) 71 | print customer.statement() 72 | 73 | 74 | -------------------------------------------------------------------------------- /labs/solutions/exercise8/sql/dvds.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sqlite3 3 | 4 | def connect(name): 5 | create = not os.path.exists(name) 6 | conn = sqlite3.connect(name) 7 | if create: 8 | cursor = conn.cursor() 9 | cursor.execute("CREATE TABLE directors (" 10 | "id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, " 11 | "name TEXT UNIQUE NOT NULL)") 12 | cursor.execute("CREATE TABLE dvds (" 13 | "id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, " 14 | "title TEXT NOT NULL, " 15 | "year INTEGER NOT NULL, " 16 | "duration INTEGER NOT NULL, " 17 | "director_id INTEGER NOT NULL, " 18 | "FOREIGN KEY (director_id) REFERENCES directors)") 19 | conn.commit() 20 | 21 | return conn 22 | 23 | def add_dvd(conn, title, year, duration, director): 24 | director_id = get_and_set_director(conn, director) 25 | cursor = conn.cursor() 26 | cursor.execute("INSERT INTO dvds " 27 | "(title, year, duration, director_id) " 28 | "VALUES (?, ?, ?, ?)", 29 | (title, year, duration, director_id)) 30 | conn.commit() 31 | 32 | def get_and_set_director(conn, director): 33 | director_id = get_director_id(conn, director) 34 | if director_id is not None: 35 | return director_id 36 | cursor = conn.cursor() 37 | cursor.execute("INSERT INTO directors (name) VALUES (?)", 38 | (director,)) 39 | conn.commit() 40 | return get_director_id(conn, director) 41 | 42 | def get_director_id(conn, director): 43 | cursor = conn.cursor() 44 | cursor.execute("SELECT id FROM directors WHERE name=?", 45 | (director,)) 46 | fields = cursor.fetchone() 47 | return fields[0] if fields is not None else None 48 | 49 | def all_dvds(conn): 50 | cursor = conn.cursor() 51 | sql = ("SELECT dvds.title, dvds.year, dvds.duration, " 52 | "directors.name FROM dvds, directors " 53 | "WHERE dvds.director_id = directors.id" 54 | " ORDER BY dvds.title") 55 | cursor.execute(sql) 56 | return [(str(fields[0]), fields[1], fields[2], str(fields[3])) for fields in cursor] 57 | 58 | def all_directors(conn): 59 | cursor = conn.cursor() 60 | sql = "SELECT name FROM directors ORDER BY name" 61 | cursor.execute(sql) 62 | return [str(fields[0]) for fields in cursor] 63 | 64 | def main(): 65 | db_name = 'dvd_library.sqlite3' 66 | conn = connect(db_name) 67 | add_dvd(conn, 'Python Tutorial 2013', 2013, 1, 'Justin') 68 | print all_directors(conn) 69 | print all_dvds(conn) 70 | 71 | if __name__ == '__main__': 72 | main() -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | TestResults 103 | *.Cache 104 | ClientBin 105 | stylecop.* 106 | ~$* 107 | *.dbmdl 108 | Generated_Code #added for RIA/Silverlight projects 109 | 110 | # Backup & report files from converting an old project file to a newer 111 | # Visual Studio version. Backup files are not needed, because we have git ;-) 112 | _UpgradeReport_Files/ 113 | Backup*/ 114 | UpgradeLog*.XML 115 | 116 | 117 | 118 | ############ 119 | ## Windows 120 | ############ 121 | 122 | # Windows image file caches 123 | Thumbs.db 124 | 125 | # Folder config file 126 | Desktop.ini 127 | 128 | 129 | ############# 130 | ## Python 131 | ############# 132 | 133 | *.py[co] 134 | 135 | # Packages 136 | *.egg 137 | *.egg-info 138 | dist 139 | build 140 | eggs 141 | parts 142 | bin 143 | var 144 | sdist 145 | develop-eggs 146 | .installed.cfg 147 | 148 | # Installer logs 149 | pip-log.txt 150 | 151 | # Unit test / coverage reports 152 | .coverage 153 | .tox 154 | 155 | #Translations 156 | *.mo 157 | 158 | #Mr Developer 159 | .mr.developer.cfg 160 | 161 | # Mac crap 162 | .DS_Store 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PyConTW2013Tutorial 2 | =================== 3 | 4 | Python Conference Taiwan 2013 Tutorial 5 | 6 | The [PyConTW](http://tw.pycon.org) organizer wishes to improve the quality and quantity of the programming cummunities in Taiwan. Though Python is their core tool and methodology, they know it's worth to learn and communicate with wide-ranging communities. Understanding cultures and ecosystem of a language takes me about three to six months. This six-hour course wraps up what I - an experienced Java developer - have learned from Python ecosystem and the agenda of the past PyConTW. 7 | 8 | Watch [PyCon Taiwan 2013 Tutorial online](http://www.slideshare.net/JustinSDK/pycon-taiwan-2013-tutorial). 9 | 10 | You can find the Traditional-Chinese edition of this tutorial in [CodeData](http://www.codedata.com.tw/python/python-tutorial-the-1st-class-1-preface). 11 | 12 | Table of Content 13 | ---------------- 14 | * The 1st class 15 | * Preface 16 | * Picking and Installing an Interpreter 17 | * Implementations 18 | * Preparing Course Environment 19 | * Where’re My Libraries? 20 | * What’s the Relationship among Distutils, Distribute and Pip? 21 | * Hello! World! 22 | * Introduction to Unicode Support 23 | * Basic Input and Output 24 | * Integrated Development Environment 25 | * Reference 26 | 27 | *** 28 | 29 | * The 2nd class 30 | * Learning Python language 31 | * Built-in Types 32 | * Numerical Types 33 | * String Type 34 | * List Type 35 | * Set Type 36 | * Dict Type 37 | * Tuple Type 38 | * if, for, while and for Comprehensions 39 | * if..else 40 | * for and while 41 | * for Comprehensions 42 | * Functions, Modules, Classes and Packages 43 | * Functions 44 | * Modules 45 | * Classes 46 | * Packages 47 | * References 48 | 49 | *** 50 | 51 | * The 3rd class 52 | * The Community 53 | * Documentation 54 | * DocStrings 55 | * Official Documentation 56 | * PyDoc 57 | * EpyDoc 58 | * Data Management Functions 59 | * Built-in Functions 60 | * reduce 61 | * Persistence 62 | * marshal, pickle, cPickle 63 | * DBM 64 | * shelve 65 | * DB-API 2.0(PEP 249) 66 | * References 67 | 68 | *** 69 | 70 | * The 4th class 71 | * Libraries vs Frameworks 72 | * Inversion of Control 73 | * Do We Need a Framework? 74 | * Getting Started with Django 75 | * Creating a Project 76 | * Creating a Database and an App 77 | * Playing API with the Python shell 78 | * Writing Your First View 79 | * Controller? or Views? 80 | * URLconf 81 | * References 82 | 83 | *** 84 | 85 | * The 5th class 86 | * Using the Template System 87 | * Writing Templates 88 | * Removing Hardcoded URLs in Templates 89 | * Namespacing URL Names 90 | * Writing a Simple Form 91 | * A Bit About CSRF 92 | * A Cross-Site Request Forgery Example 93 | * CSRF Countermeasures 94 | * Testing 95 | * assert 96 | * doctest 97 | * References 98 | 99 | *** 100 | 101 | * The 6th class 102 | * unittest(Testing Continued) 103 | * Test Case 104 | * Test Fixture 105 | * Test Suite 106 | * Test Runner 107 | * Profiling 108 | * timeit 109 | * cProfile(profile) 110 | * PyCon Taiwan 111 | * PyCon Taiwan 2012 112 | * PyCon Taiwan 2013 113 | * References 114 | 115 | *** 116 | 117 | http://openhome.cc 118 | -------------------------------------------------------------------------------- /labs/solutions/exercise9/mysite/mysite/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for mysite project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@example.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASES = { 13 | 'default': { 14 | 'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 15 | 'NAME': '', # Or path to database file if using sqlite3. 16 | # The following settings are not used with sqlite3: 17 | 'USER': '', 18 | 'PASSWORD': '', 19 | 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 20 | 'PORT': '', # Set to empty string for default. 21 | } 22 | } 23 | 24 | # Local time zone for this installation. Choices can be found here: 25 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 26 | # although not all choices may be available on all operating systems. 27 | # In a Windows environment this must be set to your system time zone. 28 | TIME_ZONE = 'America/Chicago' 29 | 30 | # Language code for this installation. All choices can be found here: 31 | # http://www.i18nguy.com/unicode/language-identifiers.html 32 | LANGUAGE_CODE = 'en-us' 33 | 34 | SITE_ID = 1 35 | 36 | # If you set this to False, Django will make some optimizations so as not 37 | # to load the internationalization machinery. 38 | USE_I18N = True 39 | 40 | # If you set this to False, Django will not format dates, numbers and 41 | # calendars according to the current locale. 42 | USE_L10N = True 43 | 44 | # If you set this to False, Django will not use timezone-aware datetimes. 45 | USE_TZ = True 46 | 47 | # Absolute filesystem path to the directory that will hold user-uploaded files. 48 | # Example: "/var/www/example.com/media/" 49 | MEDIA_ROOT = '' 50 | 51 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 52 | # trailing slash. 53 | # Examples: "http://example.com/media/", "http://media.example.com/" 54 | MEDIA_URL = '' 55 | 56 | # Absolute path to the directory static files should be collected to. 57 | # Don't put anything in this directory yourself; store your static files 58 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 59 | # Example: "/var/www/example.com/static/" 60 | STATIC_ROOT = '' 61 | 62 | # URL prefix for static files. 63 | # Example: "http://example.com/static/", "http://static.example.com/" 64 | STATIC_URL = '/static/' 65 | 66 | # Additional locations of static files 67 | STATICFILES_DIRS = ( 68 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 69 | # Always use forward slashes, even on Windows. 70 | # Don't forget to use absolute paths, not relative paths. 71 | ) 72 | 73 | # List of finder classes that know how to find static files in 74 | # various locations. 75 | STATICFILES_FINDERS = ( 76 | 'django.contrib.staticfiles.finders.FileSystemFinder', 77 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 78 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 79 | ) 80 | 81 | # Make this unique, and don't share it with anybody. 82 | SECRET_KEY = '1l$)81oh@e)xj$56aw#uy)95mzfhs68ycwr(4apdq4&5ky&i)%' 83 | 84 | # List of callables that know how to import templates from various sources. 85 | TEMPLATE_LOADERS = ( 86 | 'django.template.loaders.filesystem.Loader', 87 | 'django.template.loaders.app_directories.Loader', 88 | # 'django.template.loaders.eggs.Loader', 89 | ) 90 | 91 | MIDDLEWARE_CLASSES = ( 92 | 'django.middleware.common.CommonMiddleware', 93 | 'django.contrib.sessions.middleware.SessionMiddleware', 94 | 'django.middleware.csrf.CsrfViewMiddleware', 95 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 96 | 'django.contrib.messages.middleware.MessageMiddleware', 97 | # Uncomment the next line for simple clickjacking protection: 98 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 99 | ) 100 | 101 | ROOT_URLCONF = 'mysite.urls' 102 | 103 | # Python dotted path to the WSGI application used by Django's runserver. 104 | WSGI_APPLICATION = 'mysite.wsgi.application' 105 | 106 | TEMPLATE_DIRS = ( 107 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 108 | # Always use forward slashes, even on Windows. 109 | # Don't forget to use absolute paths, not relative paths. 110 | ) 111 | 112 | INSTALLED_APPS = ( 113 | 'django.contrib.auth', 114 | 'django.contrib.contenttypes', 115 | 'django.contrib.sessions', 116 | 'django.contrib.sites', 117 | 'django.contrib.messages', 118 | 'django.contrib.staticfiles', 119 | # Uncomment the next line to enable the admin: 120 | # 'django.contrib.admin', 121 | # Uncomment the next line to enable admin documentation: 122 | # 'django.contrib.admindocs', 123 | ) 124 | 125 | # A sample logging configuration. The only tangible logging 126 | # performed by this configuration is to send an email to 127 | # the site admins on every HTTP 500 error when DEBUG=False. 128 | # See http://docs.djangoproject.com/en/dev/topics/logging for 129 | # more details on how to customize your logging configuration. 130 | LOGGING = { 131 | 'version': 1, 132 | 'disable_existing_loggers': False, 133 | 'filters': { 134 | 'require_debug_false': { 135 | '()': 'django.utils.log.RequireDebugFalse' 136 | } 137 | }, 138 | 'handlers': { 139 | 'mail_admins': { 140 | 'level': 'ERROR', 141 | 'filters': ['require_debug_false'], 142 | 'class': 'django.utils.log.AdminEmailHandler' 143 | } 144 | }, 145 | 'loggers': { 146 | 'django.request': { 147 | 'handlers': ['mail_admins'], 148 | 'level': 'ERROR', 149 | 'propagate': True, 150 | }, 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /labs/solutions/exercise10/mysite/mysite/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for mysite project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@example.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASES = { 13 | 'default': { 14 | # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 15 | 'ENGINE': 'django.db.backends.sqlite3', 16 | # Or path to database file if using sqlite3. 17 | 'NAME': '/home/caterpillar/scripts/venv/mysite/db.sqlite3', 18 | # The following settings are not used with sqlite3: 19 | 'USER': '', # Your database username (not used for SQLite). 20 | 'PASSWORD': '', # Your database password (not used for SQLite). 21 | # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 22 | 'HOST': '', 23 | 'PORT': '', # Set to empty string for default. 24 | } 25 | } 26 | 27 | # Local time zone for this installation. Choices can be found here: 28 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 29 | # although not all choices may be available on all operating systems. 30 | # In a Windows environment this must be set to your system time zone. 31 | TIME_ZONE = 'America/Chicago' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.i18nguy.com/unicode/language-identifiers.html 35 | LANGUAGE_CODE = 'en-us' 36 | 37 | SITE_ID = 1 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # If you set this to False, Django will not format dates, numbers and 44 | # calendars according to the current locale. 45 | USE_L10N = True 46 | 47 | # If you set this to False, Django will not use timezone-aware datetimes. 48 | USE_TZ = True 49 | 50 | # Absolute filesystem path to the directory that will hold user-uploaded files. 51 | # Example: "/var/www/example.com/media/" 52 | MEDIA_ROOT = '' 53 | 54 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 55 | # trailing slash. 56 | # Examples: "http://example.com/media/", "http://media.example.com/" 57 | MEDIA_URL = '' 58 | 59 | # Absolute path to the directory static files should be collected to. 60 | # Don't put anything in this directory yourself; store your static files 61 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 62 | # Example: "/var/www/example.com/static/" 63 | STATIC_ROOT = '' 64 | 65 | # URL prefix for static files. 66 | # Example: "http://example.com/static/", "http://static.example.com/" 67 | STATIC_URL = '/static/' 68 | 69 | # Additional locations of static files 70 | STATICFILES_DIRS = ( 71 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 72 | # Always use forward slashes, even on Windows. 73 | # Don't forget to use absolute paths, not relative paths. 74 | ) 75 | 76 | # List of finder classes that know how to find static files in 77 | # various locations. 78 | STATICFILES_FINDERS = ( 79 | 'django.contrib.staticfiles.finders.FileSystemFinder', 80 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 81 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 82 | ) 83 | 84 | # Make this unique, and don't share it with anybody. 85 | SECRET_KEY = '#e(1$zso3c=f((^_&(*4wkjjq2!1xex%z#!1+bnr$d-xu31epw' 86 | 87 | # List of callables that know how to import templates from various sources. 88 | TEMPLATE_LOADERS = ( 89 | 'django.template.loaders.filesystem.Loader', 90 | 'django.template.loaders.app_directories.Loader', 91 | # 'django.template.loaders.eggs.Loader', 92 | ) 93 | 94 | MIDDLEWARE_CLASSES = ( 95 | 'django.middleware.common.CommonMiddleware', 96 | 'django.contrib.sessions.middleware.SessionMiddleware', 97 | 'django.middleware.csrf.CsrfViewMiddleware', 98 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 99 | 'django.contrib.messages.middleware.MessageMiddleware', 100 | # Uncomment the next line for simple clickjacking protection: 101 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 102 | ) 103 | 104 | ROOT_URLCONF = 'mysite.urls' 105 | 106 | # Python dotted path to the WSGI application used by Django's runserver. 107 | WSGI_APPLICATION = 'mysite.wsgi.application' 108 | 109 | TEMPLATE_DIRS = ( 110 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 111 | # Always use forward slashes, even on Windows. 112 | # Don't forget to use absolute paths, not relative paths. 113 | ) 114 | 115 | INSTALLED_APPS = ( 116 | 'django.contrib.auth', 117 | 'django.contrib.contenttypes', 118 | 'django.contrib.sessions', 119 | 'django.contrib.sites', 120 | 'django.contrib.messages', 121 | 'django.contrib.staticfiles', 122 | # Uncomment the next line to enable the admin: 123 | # 'django.contrib.admin', 124 | # Uncomment the next line to enable admin documentation: 125 | # 'django.contrib.admindocs', 126 | 'polls' 127 | ) 128 | 129 | # A sample logging configuration. The only tangible logging 130 | # performed by this configuration is to send an email to 131 | # the site admins on every HTTP 500 error when DEBUG=False. 132 | # See http://docs.djangoproject.com/en/dev/topics/logging for 133 | # more details on how to customize your logging configuration. 134 | LOGGING = { 135 | 'version': 1, 136 | 'disable_existing_loggers': False, 137 | 'filters': { 138 | 'require_debug_false': { 139 | '()': 'django.utils.log.RequireDebugFalse' 140 | } 141 | }, 142 | 'handlers': { 143 | 'mail_admins': { 144 | 'level': 'ERROR', 145 | 'filters': ['require_debug_false'], 146 | 'class': 'django.utils.log.AdminEmailHandler' 147 | } 148 | }, 149 | 'loggers': { 150 | 'django.request': { 151 | 'handlers': ['mail_admins'], 152 | 'level': 'ERROR', 153 | 'propagate': True, 154 | }, 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /labs/solutions/exercise11/mysite/mysite/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for mysite project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@example.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASES = { 13 | 'default': { 14 | # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 15 | 'ENGINE': 'django.db.backends.sqlite3', 16 | # Or path to database file if using sqlite3. 17 | 'NAME': '/home/caterpillar/scripts/venv/mysite/db.sqlite3', 18 | # The following settings are not used with sqlite3: 19 | 'USER': '', # Your database username (not used for SQLite). 20 | 'PASSWORD': '', # Your database password (not used for SQLite). 21 | # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 22 | 'HOST': '', 23 | 'PORT': '', # Set to empty string for default. 24 | } 25 | } 26 | 27 | # Local time zone for this installation. Choices can be found here: 28 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 29 | # although not all choices may be available on all operating systems. 30 | # In a Windows environment this must be set to your system time zone. 31 | TIME_ZONE = 'America/Chicago' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.i18nguy.com/unicode/language-identifiers.html 35 | LANGUAGE_CODE = 'en-us' 36 | 37 | SITE_ID = 1 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # If you set this to False, Django will not format dates, numbers and 44 | # calendars according to the current locale. 45 | USE_L10N = True 46 | 47 | # If you set this to False, Django will not use timezone-aware datetimes. 48 | USE_TZ = True 49 | 50 | # Absolute filesystem path to the directory that will hold user-uploaded files. 51 | # Example: "/var/www/example.com/media/" 52 | MEDIA_ROOT = '' 53 | 54 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 55 | # trailing slash. 56 | # Examples: "http://example.com/media/", "http://media.example.com/" 57 | MEDIA_URL = '' 58 | 59 | # Absolute path to the directory static files should be collected to. 60 | # Don't put anything in this directory yourself; store your static files 61 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 62 | # Example: "/var/www/example.com/static/" 63 | STATIC_ROOT = '' 64 | 65 | # URL prefix for static files. 66 | # Example: "http://example.com/static/", "http://static.example.com/" 67 | STATIC_URL = '/static/' 68 | 69 | # Additional locations of static files 70 | STATICFILES_DIRS = ( 71 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 72 | # Always use forward slashes, even on Windows. 73 | # Don't forget to use absolute paths, not relative paths. 74 | ) 75 | 76 | # List of finder classes that know how to find static files in 77 | # various locations. 78 | STATICFILES_FINDERS = ( 79 | 'django.contrib.staticfiles.finders.FileSystemFinder', 80 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 81 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 82 | ) 83 | 84 | # Make this unique, and don't share it with anybody. 85 | SECRET_KEY = '#e(1$zso3c=f((^_&(*4wkjjq2!1xex%z#!1+bnr$d-xu31epw' 86 | 87 | # List of callables that know how to import templates from various sources. 88 | TEMPLATE_LOADERS = ( 89 | 'django.template.loaders.filesystem.Loader', 90 | 'django.template.loaders.app_directories.Loader', 91 | # 'django.template.loaders.eggs.Loader', 92 | ) 93 | 94 | MIDDLEWARE_CLASSES = ( 95 | 'django.middleware.common.CommonMiddleware', 96 | 'django.contrib.sessions.middleware.SessionMiddleware', 97 | 'django.middleware.csrf.CsrfViewMiddleware', 98 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 99 | 'django.contrib.messages.middleware.MessageMiddleware', 100 | # Uncomment the next line for simple clickjacking protection: 101 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 102 | ) 103 | 104 | ROOT_URLCONF = 'mysite.urls' 105 | 106 | # Python dotted path to the WSGI application used by Django's runserver. 107 | WSGI_APPLICATION = 'mysite.wsgi.application' 108 | 109 | TEMPLATE_DIRS = ( 110 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 111 | # Always use forward slashes, even on Windows. 112 | # Don't forget to use absolute paths, not relative paths. 113 | ) 114 | 115 | INSTALLED_APPS = ( 116 | 'django.contrib.auth', 117 | 'django.contrib.contenttypes', 118 | 'django.contrib.sessions', 119 | 'django.contrib.sites', 120 | 'django.contrib.messages', 121 | 'django.contrib.staticfiles', 122 | # Uncomment the next line to enable the admin: 123 | # 'django.contrib.admin', 124 | # Uncomment the next line to enable admin documentation: 125 | # 'django.contrib.admindocs', 126 | 'polls' 127 | ) 128 | 129 | # A sample logging configuration. The only tangible logging 130 | # performed by this configuration is to send an email to 131 | # the site admins on every HTTP 500 error when DEBUG=False. 132 | # See http://docs.djangoproject.com/en/dev/topics/logging for 133 | # more details on how to customize your logging configuration. 134 | LOGGING = { 135 | 'version': 1, 136 | 'disable_existing_loggers': False, 137 | 'filters': { 138 | 'require_debug_false': { 139 | '()': 'django.utils.log.RequireDebugFalse' 140 | } 141 | }, 142 | 'handlers': { 143 | 'mail_admins': { 144 | 'level': 'ERROR', 145 | 'filters': ['require_debug_false'], 146 | 'class': 'django.utils.log.AdminEmailHandler' 147 | } 148 | }, 149 | 'loggers': { 150 | 'django.request': { 151 | 'handlers': ['mail_admins'], 152 | 'level': 'ERROR', 153 | 'propagate': True, 154 | }, 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /labs/solutions/exercise12/mysite/mysite/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for mysite project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@example.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASES = { 13 | 'default': { 14 | # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 15 | 'ENGINE': 'django.db.backends.sqlite3', 16 | # Or path to database file if using sqlite3. 17 | 'NAME': '/home/caterpillar/scripts/venv/mysite/db.sqlite3', 18 | # The following settings are not used with sqlite3: 19 | 'USER': '', # Your database username (not used for SQLite). 20 | 'PASSWORD': '', # Your database password (not used for SQLite). 21 | # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 22 | 'HOST': '', 23 | 'PORT': '', # Set to empty string for default. 24 | } 25 | } 26 | 27 | # Local time zone for this installation. Choices can be found here: 28 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 29 | # although not all choices may be available on all operating systems. 30 | # In a Windows environment this must be set to your system time zone. 31 | TIME_ZONE = 'America/Chicago' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.i18nguy.com/unicode/language-identifiers.html 35 | LANGUAGE_CODE = 'en-us' 36 | 37 | SITE_ID = 1 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # If you set this to False, Django will not format dates, numbers and 44 | # calendars according to the current locale. 45 | USE_L10N = True 46 | 47 | # If you set this to False, Django will not use timezone-aware datetimes. 48 | USE_TZ = True 49 | 50 | # Absolute filesystem path to the directory that will hold user-uploaded files. 51 | # Example: "/var/www/example.com/media/" 52 | MEDIA_ROOT = '' 53 | 54 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 55 | # trailing slash. 56 | # Examples: "http://example.com/media/", "http://media.example.com/" 57 | MEDIA_URL = '' 58 | 59 | # Absolute path to the directory static files should be collected to. 60 | # Don't put anything in this directory yourself; store your static files 61 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 62 | # Example: "/var/www/example.com/static/" 63 | STATIC_ROOT = '' 64 | 65 | # URL prefix for static files. 66 | # Example: "http://example.com/static/", "http://static.example.com/" 67 | STATIC_URL = '/static/' 68 | 69 | # Additional locations of static files 70 | STATICFILES_DIRS = ( 71 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 72 | # Always use forward slashes, even on Windows. 73 | # Don't forget to use absolute paths, not relative paths. 74 | ) 75 | 76 | # List of finder classes that know how to find static files in 77 | # various locations. 78 | STATICFILES_FINDERS = ( 79 | 'django.contrib.staticfiles.finders.FileSystemFinder', 80 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 81 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 82 | ) 83 | 84 | # Make this unique, and don't share it with anybody. 85 | SECRET_KEY = '#e(1$zso3c=f((^_&(*4wkjjq2!1xex%z#!1+bnr$d-xu31epw' 86 | 87 | # List of callables that know how to import templates from various sources. 88 | TEMPLATE_LOADERS = ( 89 | 'django.template.loaders.filesystem.Loader', 90 | 'django.template.loaders.app_directories.Loader', 91 | # 'django.template.loaders.eggs.Loader', 92 | ) 93 | 94 | MIDDLEWARE_CLASSES = ( 95 | 'django.middleware.common.CommonMiddleware', 96 | 'django.contrib.sessions.middleware.SessionMiddleware', 97 | 'django.middleware.csrf.CsrfViewMiddleware', 98 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 99 | 'django.contrib.messages.middleware.MessageMiddleware', 100 | # Uncomment the next line for simple clickjacking protection: 101 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 102 | ) 103 | 104 | ROOT_URLCONF = 'mysite.urls' 105 | 106 | # Python dotted path to the WSGI application used by Django's runserver. 107 | WSGI_APPLICATION = 'mysite.wsgi.application' 108 | 109 | TEMPLATE_DIRS = ( 110 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 111 | # Always use forward slashes, even on Windows. 112 | # Don't forget to use absolute paths, not relative paths. 113 | ) 114 | 115 | INSTALLED_APPS = ( 116 | 'django.contrib.auth', 117 | 'django.contrib.contenttypes', 118 | 'django.contrib.sessions', 119 | 'django.contrib.sites', 120 | 'django.contrib.messages', 121 | 'django.contrib.staticfiles', 122 | # Uncomment the next line to enable the admin: 123 | # 'django.contrib.admin', 124 | # Uncomment the next line to enable admin documentation: 125 | # 'django.contrib.admindocs', 126 | 'polls' 127 | ) 128 | 129 | # A sample logging configuration. The only tangible logging 130 | # performed by this configuration is to send an email to 131 | # the site admins on every HTTP 500 error when DEBUG=False. 132 | # See http://docs.djangoproject.com/en/dev/topics/logging for 133 | # more details on how to customize your logging configuration. 134 | LOGGING = { 135 | 'version': 1, 136 | 'disable_existing_loggers': False, 137 | 'filters': { 138 | 'require_debug_false': { 139 | '()': 'django.utils.log.RequireDebugFalse' 140 | } 141 | }, 142 | 'handlers': { 143 | 'mail_admins': { 144 | 'level': 'ERROR', 145 | 'filters': ['require_debug_false'], 146 | 'class': 'django.utils.log.AdminEmailHandler' 147 | } 148 | }, 149 | 'loggers': { 150 | 'django.request': { 151 | 'handlers': ['mail_admins'], 152 | 'level': 'ERROR', 153 | 'propagate': True, 154 | }, 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /labs/solutions/exercise13/mysite/mysite/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for mysite project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@example.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASES = { 13 | 'default': { 14 | # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 15 | 'ENGINE': 'django.db.backends.sqlite3', 16 | # Or path to database file if using sqlite3. 17 | 'NAME': '/home/caterpillar/scripts/venv/mysite/db.sqlite3', 18 | # The following settings are not used with sqlite3: 19 | 'USER': '', # Your database username (not used for SQLite). 20 | 'PASSWORD': '', # Your database password (not used for SQLite). 21 | # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 22 | 'HOST': '', 23 | 'PORT': '', # Set to empty string for default. 24 | } 25 | } 26 | 27 | # Local time zone for this installation. Choices can be found here: 28 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 29 | # although not all choices may be available on all operating systems. 30 | # In a Windows environment this must be set to your system time zone. 31 | TIME_ZONE = 'America/Chicago' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.i18nguy.com/unicode/language-identifiers.html 35 | LANGUAGE_CODE = 'en-us' 36 | 37 | SITE_ID = 1 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # If you set this to False, Django will not format dates, numbers and 44 | # calendars according to the current locale. 45 | USE_L10N = True 46 | 47 | # If you set this to False, Django will not use timezone-aware datetimes. 48 | USE_TZ = True 49 | 50 | # Absolute filesystem path to the directory that will hold user-uploaded files. 51 | # Example: "/var/www/example.com/media/" 52 | MEDIA_ROOT = '' 53 | 54 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 55 | # trailing slash. 56 | # Examples: "http://example.com/media/", "http://media.example.com/" 57 | MEDIA_URL = '' 58 | 59 | # Absolute path to the directory static files should be collected to. 60 | # Don't put anything in this directory yourself; store your static files 61 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 62 | # Example: "/var/www/example.com/static/" 63 | STATIC_ROOT = '' 64 | 65 | # URL prefix for static files. 66 | # Example: "http://example.com/static/", "http://static.example.com/" 67 | STATIC_URL = '/static/' 68 | 69 | # Additional locations of static files 70 | STATICFILES_DIRS = ( 71 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 72 | # Always use forward slashes, even on Windows. 73 | # Don't forget to use absolute paths, not relative paths. 74 | ) 75 | 76 | # List of finder classes that know how to find static files in 77 | # various locations. 78 | STATICFILES_FINDERS = ( 79 | 'django.contrib.staticfiles.finders.FileSystemFinder', 80 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 81 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 82 | ) 83 | 84 | # Make this unique, and don't share it with anybody. 85 | SECRET_KEY = '#e(1$zso3c=f((^_&(*4wkjjq2!1xex%z#!1+bnr$d-xu31epw' 86 | 87 | # List of callables that know how to import templates from various sources. 88 | TEMPLATE_LOADERS = ( 89 | 'django.template.loaders.filesystem.Loader', 90 | 'django.template.loaders.app_directories.Loader', 91 | # 'django.template.loaders.eggs.Loader', 92 | ) 93 | 94 | MIDDLEWARE_CLASSES = ( 95 | 'django.middleware.common.CommonMiddleware', 96 | 'django.contrib.sessions.middleware.SessionMiddleware', 97 | 'django.middleware.csrf.CsrfViewMiddleware', 98 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 99 | 'django.contrib.messages.middleware.MessageMiddleware', 100 | # Uncomment the next line for simple clickjacking protection: 101 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 102 | ) 103 | 104 | ROOT_URLCONF = 'mysite.urls' 105 | 106 | # Python dotted path to the WSGI application used by Django's runserver. 107 | WSGI_APPLICATION = 'mysite.wsgi.application' 108 | 109 | TEMPLATE_DIRS = ( 110 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 111 | # Always use forward slashes, even on Windows. 112 | # Don't forget to use absolute paths, not relative paths. 113 | ) 114 | 115 | INSTALLED_APPS = ( 116 | 'django.contrib.auth', 117 | 'django.contrib.contenttypes', 118 | 'django.contrib.sessions', 119 | 'django.contrib.sites', 120 | 'django.contrib.messages', 121 | 'django.contrib.staticfiles', 122 | # Uncomment the next line to enable the admin: 123 | # 'django.contrib.admin', 124 | # Uncomment the next line to enable admin documentation: 125 | # 'django.contrib.admindocs', 126 | 'polls' 127 | ) 128 | 129 | # A sample logging configuration. The only tangible logging 130 | # performed by this configuration is to send an email to 131 | # the site admins on every HTTP 500 error when DEBUG=False. 132 | # See http://docs.djangoproject.com/en/dev/topics/logging for 133 | # more details on how to customize your logging configuration. 134 | LOGGING = { 135 | 'version': 1, 136 | 'disable_existing_loggers': False, 137 | 'filters': { 138 | 'require_debug_false': { 139 | '()': 'django.utils.log.RequireDebugFalse' 140 | } 141 | }, 142 | 'handlers': { 143 | 'mail_admins': { 144 | 'level': 'ERROR', 145 | 'filters': ['require_debug_false'], 146 | 'class': 'django.utils.log.AdminEmailHandler' 147 | } 148 | }, 149 | 'loggers': { 150 | 'django.request': { 151 | 'handlers': ['mail_admins'], 152 | 'level': 'ERROR', 153 | 'propagate': True, 154 | }, 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /labs/resources/distribute_setup.py: -------------------------------------------------------------------------------- 1 | #!python 2 | """Bootstrap distribute installation 3 | 4 | If you want to use setuptools in your package's setup.py, just include this 5 | file in the same directory with it, and add this to the top of your setup.py:: 6 | 7 | from distribute_setup import use_setuptools 8 | use_setuptools() 9 | 10 | If you want to require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, you can do so by supplying 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import os 17 | import shutil 18 | import sys 19 | import time 20 | import fnmatch 21 | import tempfile 22 | import tarfile 23 | import optparse 24 | 25 | from distutils import log 26 | 27 | try: 28 | from site import USER_SITE 29 | except ImportError: 30 | USER_SITE = None 31 | 32 | try: 33 | import subprocess 34 | 35 | def _python_cmd(*args): 36 | args = (sys.executable,) + args 37 | return subprocess.call(args) == 0 38 | 39 | except ImportError: 40 | # will be used for python 2.3 41 | def _python_cmd(*args): 42 | args = (sys.executable,) + args 43 | # quoting arguments if windows 44 | if sys.platform == 'win32': 45 | def quote(arg): 46 | if ' ' in arg: 47 | return '"%s"' % arg 48 | return arg 49 | args = [quote(arg) for arg in args] 50 | return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 51 | 52 | DEFAULT_VERSION = "0.6.34" 53 | DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" 54 | SETUPTOOLS_FAKED_VERSION = "0.6c11" 55 | 56 | SETUPTOOLS_PKG_INFO = """\ 57 | Metadata-Version: 1.0 58 | Name: setuptools 59 | Version: %s 60 | Summary: xxxx 61 | Home-page: xxx 62 | Author: xxx 63 | Author-email: xxx 64 | License: xxx 65 | Description: xxx 66 | """ % SETUPTOOLS_FAKED_VERSION 67 | 68 | 69 | def _install(tarball, install_args=()): 70 | # extracting the tarball 71 | tmpdir = tempfile.mkdtemp() 72 | log.warn('Extracting in %s', tmpdir) 73 | old_wd = os.getcwd() 74 | try: 75 | os.chdir(tmpdir) 76 | tar = tarfile.open(tarball) 77 | _extractall(tar) 78 | tar.close() 79 | 80 | # going in the directory 81 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 82 | os.chdir(subdir) 83 | log.warn('Now working in %s', subdir) 84 | 85 | # installing 86 | log.warn('Installing Distribute') 87 | if not _python_cmd('setup.py', 'install', *install_args): 88 | log.warn('Something went wrong during the installation.') 89 | log.warn('See the error message above.') 90 | # exitcode will be 2 91 | return 2 92 | finally: 93 | os.chdir(old_wd) 94 | shutil.rmtree(tmpdir) 95 | 96 | 97 | def _build_egg(egg, tarball, to_dir): 98 | # extracting the tarball 99 | tmpdir = tempfile.mkdtemp() 100 | log.warn('Extracting in %s', tmpdir) 101 | old_wd = os.getcwd() 102 | try: 103 | os.chdir(tmpdir) 104 | tar = tarfile.open(tarball) 105 | _extractall(tar) 106 | tar.close() 107 | 108 | # going in the directory 109 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 110 | os.chdir(subdir) 111 | log.warn('Now working in %s', subdir) 112 | 113 | # building an egg 114 | log.warn('Building a Distribute egg in %s', to_dir) 115 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) 116 | 117 | finally: 118 | os.chdir(old_wd) 119 | shutil.rmtree(tmpdir) 120 | # returning the result 121 | log.warn(egg) 122 | if not os.path.exists(egg): 123 | raise IOError('Could not build the egg.') 124 | 125 | 126 | def _do_download(version, download_base, to_dir, download_delay): 127 | egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' 128 | % (version, sys.version_info[0], sys.version_info[1])) 129 | if not os.path.exists(egg): 130 | tarball = download_setuptools(version, download_base, 131 | to_dir, download_delay) 132 | _build_egg(egg, tarball, to_dir) 133 | sys.path.insert(0, egg) 134 | import setuptools 135 | setuptools.bootstrap_install_from = egg 136 | 137 | 138 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 139 | to_dir=os.curdir, download_delay=15, no_fake=True): 140 | # making sure we use the absolute path 141 | to_dir = os.path.abspath(to_dir) 142 | was_imported = 'pkg_resources' in sys.modules or \ 143 | 'setuptools' in sys.modules 144 | try: 145 | try: 146 | import pkg_resources 147 | if not hasattr(pkg_resources, '_distribute'): 148 | if not no_fake: 149 | _fake_setuptools() 150 | raise ImportError 151 | except ImportError: 152 | return _do_download(version, download_base, to_dir, download_delay) 153 | try: 154 | pkg_resources.require("distribute>=" + version) 155 | return 156 | except pkg_resources.VersionConflict: 157 | e = sys.exc_info()[1] 158 | if was_imported: 159 | sys.stderr.write( 160 | "The required version of distribute (>=%s) is not available,\n" 161 | "and can't be installed while this script is running. Please\n" 162 | "install a more recent version first, using\n" 163 | "'easy_install -U distribute'." 164 | "\n\n(Currently using %r)\n" % (version, e.args[0])) 165 | sys.exit(2) 166 | else: 167 | del pkg_resources, sys.modules['pkg_resources'] # reload ok 168 | return _do_download(version, download_base, to_dir, 169 | download_delay) 170 | except pkg_resources.DistributionNotFound: 171 | return _do_download(version, download_base, to_dir, 172 | download_delay) 173 | finally: 174 | if not no_fake: 175 | _create_fake_setuptools_pkg_info(to_dir) 176 | 177 | 178 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 179 | to_dir=os.curdir, delay=15): 180 | """Download distribute from a specified location and return its filename 181 | 182 | `version` should be a valid distribute version number that is available 183 | as an egg for download under the `download_base` URL (which should end 184 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 185 | `delay` is the number of seconds to pause before an actual download 186 | attempt. 187 | """ 188 | # making sure we use the absolute path 189 | to_dir = os.path.abspath(to_dir) 190 | try: 191 | from urllib.request import urlopen 192 | except ImportError: 193 | from urllib2 import urlopen 194 | tgz_name = "distribute-%s.tar.gz" % version 195 | url = download_base + tgz_name 196 | saveto = os.path.join(to_dir, tgz_name) 197 | src = dst = None 198 | if not os.path.exists(saveto): # Avoid repeated downloads 199 | try: 200 | log.warn("Downloading %s", url) 201 | src = urlopen(url) 202 | # Read/write all in one block, so we don't create a corrupt file 203 | # if the download is interrupted. 204 | data = src.read() 205 | dst = open(saveto, "wb") 206 | dst.write(data) 207 | finally: 208 | if src: 209 | src.close() 210 | if dst: 211 | dst.close() 212 | return os.path.realpath(saveto) 213 | 214 | 215 | def _no_sandbox(function): 216 | def __no_sandbox(*args, **kw): 217 | try: 218 | from setuptools.sandbox import DirectorySandbox 219 | if not hasattr(DirectorySandbox, '_old'): 220 | def violation(*args): 221 | pass 222 | DirectorySandbox._old = DirectorySandbox._violation 223 | DirectorySandbox._violation = violation 224 | patched = True 225 | else: 226 | patched = False 227 | except ImportError: 228 | patched = False 229 | 230 | try: 231 | return function(*args, **kw) 232 | finally: 233 | if patched: 234 | DirectorySandbox._violation = DirectorySandbox._old 235 | del DirectorySandbox._old 236 | 237 | return __no_sandbox 238 | 239 | 240 | def _patch_file(path, content): 241 | """Will backup the file then patch it""" 242 | f = open(path) 243 | existing_content = f.read() 244 | f.close() 245 | if existing_content == content: 246 | # already patched 247 | log.warn('Already patched.') 248 | return False 249 | log.warn('Patching...') 250 | _rename_path(path) 251 | f = open(path, 'w') 252 | try: 253 | f.write(content) 254 | finally: 255 | f.close() 256 | return True 257 | 258 | _patch_file = _no_sandbox(_patch_file) 259 | 260 | 261 | def _same_content(path, content): 262 | f = open(path) 263 | existing_content = f.read() 264 | f.close() 265 | return existing_content == content 266 | 267 | 268 | def _rename_path(path): 269 | new_name = path + '.OLD.%s' % time.time() 270 | log.warn('Renaming %s to %s', path, new_name) 271 | os.rename(path, new_name) 272 | return new_name 273 | 274 | 275 | def _remove_flat_installation(placeholder): 276 | if not os.path.isdir(placeholder): 277 | log.warn('Unkown installation at %s', placeholder) 278 | return False 279 | found = False 280 | for file in os.listdir(placeholder): 281 | if fnmatch.fnmatch(file, 'setuptools*.egg-info'): 282 | found = True 283 | break 284 | if not found: 285 | log.warn('Could not locate setuptools*.egg-info') 286 | return 287 | 288 | log.warn('Moving elements out of the way...') 289 | pkg_info = os.path.join(placeholder, file) 290 | if os.path.isdir(pkg_info): 291 | patched = _patch_egg_dir(pkg_info) 292 | else: 293 | patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) 294 | 295 | if not patched: 296 | log.warn('%s already patched.', pkg_info) 297 | return False 298 | # now let's move the files out of the way 299 | for element in ('setuptools', 'pkg_resources.py', 'site.py'): 300 | element = os.path.join(placeholder, element) 301 | if os.path.exists(element): 302 | _rename_path(element) 303 | else: 304 | log.warn('Could not find the %s element of the ' 305 | 'Setuptools distribution', element) 306 | return True 307 | 308 | _remove_flat_installation = _no_sandbox(_remove_flat_installation) 309 | 310 | 311 | def _after_install(dist): 312 | log.warn('After install bootstrap.') 313 | placeholder = dist.get_command_obj('install').install_purelib 314 | _create_fake_setuptools_pkg_info(placeholder) 315 | 316 | 317 | def _create_fake_setuptools_pkg_info(placeholder): 318 | if not placeholder or not os.path.exists(placeholder): 319 | log.warn('Could not find the install location') 320 | return 321 | pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) 322 | setuptools_file = 'setuptools-%s-py%s.egg-info' % \ 323 | (SETUPTOOLS_FAKED_VERSION, pyver) 324 | pkg_info = os.path.join(placeholder, setuptools_file) 325 | if os.path.exists(pkg_info): 326 | log.warn('%s already exists', pkg_info) 327 | return 328 | 329 | log.warn('Creating %s', pkg_info) 330 | try: 331 | f = open(pkg_info, 'w') 332 | except EnvironmentError: 333 | log.warn("Don't have permissions to write %s, skipping", pkg_info) 334 | return 335 | try: 336 | f.write(SETUPTOOLS_PKG_INFO) 337 | finally: 338 | f.close() 339 | 340 | pth_file = os.path.join(placeholder, 'setuptools.pth') 341 | log.warn('Creating %s', pth_file) 342 | f = open(pth_file, 'w') 343 | try: 344 | f.write(os.path.join(os.curdir, setuptools_file)) 345 | finally: 346 | f.close() 347 | 348 | _create_fake_setuptools_pkg_info = _no_sandbox( 349 | _create_fake_setuptools_pkg_info 350 | ) 351 | 352 | 353 | def _patch_egg_dir(path): 354 | # let's check if it's already patched 355 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 356 | if os.path.exists(pkg_info): 357 | if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): 358 | log.warn('%s already patched.', pkg_info) 359 | return False 360 | _rename_path(path) 361 | os.mkdir(path) 362 | os.mkdir(os.path.join(path, 'EGG-INFO')) 363 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 364 | f = open(pkg_info, 'w') 365 | try: 366 | f.write(SETUPTOOLS_PKG_INFO) 367 | finally: 368 | f.close() 369 | return True 370 | 371 | _patch_egg_dir = _no_sandbox(_patch_egg_dir) 372 | 373 | 374 | def _before_install(): 375 | log.warn('Before install bootstrap.') 376 | _fake_setuptools() 377 | 378 | 379 | def _under_prefix(location): 380 | if 'install' not in sys.argv: 381 | return True 382 | args = sys.argv[sys.argv.index('install') + 1:] 383 | for index, arg in enumerate(args): 384 | for option in ('--root', '--prefix'): 385 | if arg.startswith('%s=' % option): 386 | top_dir = arg.split('root=')[-1] 387 | return location.startswith(top_dir) 388 | elif arg == option: 389 | if len(args) > index: 390 | top_dir = args[index + 1] 391 | return location.startswith(top_dir) 392 | if arg == '--user' and USER_SITE is not None: 393 | return location.startswith(USER_SITE) 394 | return True 395 | 396 | 397 | def _fake_setuptools(): 398 | log.warn('Scanning installed packages') 399 | try: 400 | import pkg_resources 401 | except ImportError: 402 | # we're cool 403 | log.warn('Setuptools or Distribute does not seem to be installed.') 404 | return 405 | ws = pkg_resources.working_set 406 | try: 407 | setuptools_dist = ws.find( 408 | pkg_resources.Requirement.parse('setuptools', replacement=False) 409 | ) 410 | except TypeError: 411 | # old distribute API 412 | setuptools_dist = ws.find( 413 | pkg_resources.Requirement.parse('setuptools') 414 | ) 415 | 416 | if setuptools_dist is None: 417 | log.warn('No setuptools distribution found') 418 | return 419 | # detecting if it was already faked 420 | setuptools_location = setuptools_dist.location 421 | log.warn('Setuptools installation detected at %s', setuptools_location) 422 | 423 | # if --root or --preix was provided, and if 424 | # setuptools is not located in them, we don't patch it 425 | if not _under_prefix(setuptools_location): 426 | log.warn('Not patching, --root or --prefix is installing Distribute' 427 | ' in another location') 428 | return 429 | 430 | # let's see if its an egg 431 | if not setuptools_location.endswith('.egg'): 432 | log.warn('Non-egg installation') 433 | res = _remove_flat_installation(setuptools_location) 434 | if not res: 435 | return 436 | else: 437 | log.warn('Egg installation') 438 | pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') 439 | if (os.path.exists(pkg_info) and 440 | _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): 441 | log.warn('Already patched.') 442 | return 443 | log.warn('Patching...') 444 | # let's create a fake egg replacing setuptools one 445 | res = _patch_egg_dir(setuptools_location) 446 | if not res: 447 | return 448 | log.warn('Patching complete.') 449 | _relaunch() 450 | 451 | 452 | def _relaunch(): 453 | log.warn('Relaunching...') 454 | # we have to relaunch the process 455 | # pip marker to avoid a relaunch bug 456 | _cmd1 = ['-c', 'install', '--single-version-externally-managed'] 457 | _cmd2 = ['-c', 'install', '--record'] 458 | if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2: 459 | sys.argv[0] = 'setup.py' 460 | args = [sys.executable] + sys.argv 461 | sys.exit(subprocess.call(args)) 462 | 463 | 464 | def _extractall(self, path=".", members=None): 465 | """Extract all members from the archive to the current working 466 | directory and set owner, modification time and permissions on 467 | directories afterwards. `path' specifies a different directory 468 | to extract to. `members' is optional and must be a subset of the 469 | list returned by getmembers(). 470 | """ 471 | import copy 472 | import operator 473 | from tarfile import ExtractError 474 | directories = [] 475 | 476 | if members is None: 477 | members = self 478 | 479 | for tarinfo in members: 480 | if tarinfo.isdir(): 481 | # Extract directories with a safe mode. 482 | directories.append(tarinfo) 483 | tarinfo = copy.copy(tarinfo) 484 | tarinfo.mode = 448 # decimal for oct 0700 485 | self.extract(tarinfo, path) 486 | 487 | # Reverse sort directories. 488 | if sys.version_info < (2, 4): 489 | def sorter(dir1, dir2): 490 | return cmp(dir1.name, dir2.name) 491 | directories.sort(sorter) 492 | directories.reverse() 493 | else: 494 | directories.sort(key=operator.attrgetter('name'), reverse=True) 495 | 496 | # Set correct owner, mtime and filemode on directories. 497 | for tarinfo in directories: 498 | dirpath = os.path.join(path, tarinfo.name) 499 | try: 500 | self.chown(tarinfo, dirpath) 501 | self.utime(tarinfo, dirpath) 502 | self.chmod(tarinfo, dirpath) 503 | except ExtractError: 504 | e = sys.exc_info()[1] 505 | if self.errorlevel > 1: 506 | raise 507 | else: 508 | self._dbg(1, "tarfile: %s" % e) 509 | 510 | 511 | def _build_install_args(options): 512 | """ 513 | Build the arguments to 'python setup.py install' on the distribute package 514 | """ 515 | install_args = [] 516 | if options.user_install: 517 | if sys.version_info < (2, 6): 518 | log.warn("--user requires Python 2.6 or later") 519 | raise SystemExit(1) 520 | install_args.append('--user') 521 | return install_args 522 | 523 | def _parse_args(): 524 | """ 525 | Parse the command line for options 526 | """ 527 | parser = optparse.OptionParser() 528 | parser.add_option( 529 | '--user', dest='user_install', action='store_true', default=False, 530 | help='install in user site package (requires Python 2.6 or later)') 531 | parser.add_option( 532 | '--download-base', dest='download_base', metavar="URL", 533 | default=DEFAULT_URL, 534 | help='alternative URL from where to download the distribute package') 535 | options, args = parser.parse_args() 536 | # positional arguments are ignored 537 | return options 538 | 539 | def main(version=DEFAULT_VERSION): 540 | """Install or upgrade setuptools and EasyInstall""" 541 | options = _parse_args() 542 | tarball = download_setuptools(download_base=options.download_base) 543 | return _install(tarball, _build_install_args(options)) 544 | 545 | if __name__ == '__main__': 546 | sys.exit(main()) 547 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial-ShareAlike 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More_considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International 58 | Public License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial-ShareAlike 4.0 International Public License 63 | ("Public License"). To the extent this Public License may be 64 | interpreted as a contract, You are granted the Licensed Rights in 65 | consideration of Your acceptance of these terms and conditions, and the 66 | Licensor grants You such rights in consideration of benefits the 67 | Licensor receives from making the Licensed Material available under 68 | these terms and conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Adapter's License means the license You apply to Your Copyright 84 | and Similar Rights in Your contributions to Adapted Material in 85 | accordance with the terms and conditions of this Public License. 86 | 87 | c. BY-NC-SA Compatible License means a license listed at 88 | creativecommons.org/compatiblelicenses, approved by Creative 89 | Commons as essentially the equivalent of this Public License. 90 | 91 | d. Copyright and Similar Rights means copyright and/or similar rights 92 | closely related to copyright including, without limitation, 93 | performance, broadcast, sound recording, and Sui Generis Database 94 | Rights, without regard to how the rights are labeled or 95 | categorized. For purposes of this Public License, the rights 96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 97 | Rights. 98 | 99 | e. Effective Technological Measures means those measures that, in the 100 | absence of proper authority, may not be circumvented under laws 101 | fulfilling obligations under Article 11 of the WIPO Copyright 102 | Treaty adopted on December 20, 1996, and/or similar international 103 | agreements. 104 | 105 | f. Exceptions and Limitations means fair use, fair dealing, and/or 106 | any other exception or limitation to Copyright and Similar Rights 107 | that applies to Your use of the Licensed Material. 108 | 109 | g. License Elements means the license attributes listed in the name 110 | of a Creative Commons Public License. The License Elements of this 111 | Public License are Attribution, NonCommercial, and ShareAlike. 112 | 113 | h. Licensed Material means the artistic or literary work, database, 114 | or other material to which the Licensor applied this Public 115 | License. 116 | 117 | i. Licensed Rights means the rights granted to You subject to the 118 | terms and conditions of this Public License, which are limited to 119 | all Copyright and Similar Rights that apply to Your use of the 120 | Licensed Material and that the Licensor has authority to license. 121 | 122 | j. Licensor means the individual(s) or entity(ies) granting rights 123 | under this Public License. 124 | 125 | k. NonCommercial means not primarily intended for or directed towards 126 | commercial advantage or monetary compensation. For purposes of 127 | this Public License, the exchange of the Licensed Material for 128 | other material subject to Copyright and Similar Rights by digital 129 | file-sharing or similar means is NonCommercial provided there is 130 | no payment of monetary compensation in connection with the 131 | exchange. 132 | 133 | l. Share means to provide material to the public by any means or 134 | process that requires permission under the Licensed Rights, such 135 | as reproduction, public display, public performance, distribution, 136 | dissemination, communication, or importation, and to make material 137 | available to the public including in ways that members of the 138 | public may access the material from a place and at a time 139 | individually chosen by them. 140 | 141 | m. Sui Generis Database Rights means rights other than copyright 142 | resulting from Directive 96/9/EC of the European Parliament and of 143 | the Council of 11 March 1996 on the legal protection of databases, 144 | as amended and/or succeeded, as well as other essentially 145 | equivalent rights anywhere in the world. 146 | 147 | n. You means the individual or entity exercising the Licensed Rights 148 | under this Public License. Your has a corresponding meaning. 149 | 150 | 151 | Section 2 -- Scope. 152 | 153 | a. License grant. 154 | 155 | 1. Subject to the terms and conditions of this Public License, 156 | the Licensor hereby grants You a worldwide, royalty-free, 157 | non-sublicensable, non-exclusive, irrevocable license to 158 | exercise the Licensed Rights in the Licensed Material to: 159 | 160 | a. reproduce and Share the Licensed Material, in whole or 161 | in part, for NonCommercial purposes only; and 162 | 163 | b. produce, reproduce, and Share Adapted Material for 164 | NonCommercial purposes only. 165 | 166 | 2. Exceptions and Limitations. For the avoidance of doubt, where 167 | Exceptions and Limitations apply to Your use, this Public 168 | License does not apply, and You do not need to comply with 169 | its terms and conditions. 170 | 171 | 3. Term. The term of this Public License is specified in Section 172 | 6(a). 173 | 174 | 4. Media and formats; technical modifications allowed. The 175 | Licensor authorizes You to exercise the Licensed Rights in 176 | all media and formats whether now known or hereafter created, 177 | and to make technical modifications necessary to do so. The 178 | Licensor waives and/or agrees not to assert any right or 179 | authority to forbid You from making technical modifications 180 | necessary to exercise the Licensed Rights, including 181 | technical modifications necessary to circumvent Effective 182 | Technological Measures. For purposes of this Public License, 183 | simply making modifications authorized by this Section 2(a) 184 | (4) never produces Adapted Material. 185 | 186 | 5. Downstream recipients. 187 | 188 | a. Offer from the Licensor -- Licensed Material. Every 189 | recipient of the Licensed Material automatically 190 | receives an offer from the Licensor to exercise the 191 | Licensed Rights under the terms and conditions of this 192 | Public License. 193 | 194 | b. Additional offer from the Licensor -- Adapted Material. 195 | Every recipient of Adapted Material from You 196 | automatically receives an offer from the Licensor to 197 | exercise the Licensed Rights in the Adapted Material 198 | under the conditions of the Adapter's License You apply. 199 | 200 | c. No downstream restrictions. You may not offer or impose 201 | any additional or different terms or conditions on, or 202 | apply any Effective Technological Measures to, the 203 | Licensed Material if doing so restricts exercise of the 204 | Licensed Rights by any recipient of the Licensed 205 | Material. 206 | 207 | 6. No endorsement. Nothing in this Public License constitutes or 208 | may be construed as permission to assert or imply that You 209 | are, or that Your use of the Licensed Material is, connected 210 | with, or sponsored, endorsed, or granted official status by, 211 | the Licensor or others designated to receive attribution as 212 | provided in Section 3(a)(1)(A)(i). 213 | 214 | b. Other rights. 215 | 216 | 1. Moral rights, such as the right of integrity, are not 217 | licensed under this Public License, nor are publicity, 218 | privacy, and/or other similar personality rights; however, to 219 | the extent possible, the Licensor waives and/or agrees not to 220 | assert any such rights held by the Licensor to the limited 221 | extent necessary to allow You to exercise the Licensed 222 | Rights, but not otherwise. 223 | 224 | 2. Patent and trademark rights are not licensed under this 225 | Public License. 226 | 227 | 3. To the extent possible, the Licensor waives any right to 228 | collect royalties from You for the exercise of the Licensed 229 | Rights, whether directly or through a collecting society 230 | under any voluntary or waivable statutory or compulsory 231 | licensing scheme. In all other cases the Licensor expressly 232 | reserves any right to collect such royalties, including when 233 | the Licensed Material is used other than for NonCommercial 234 | purposes. 235 | 236 | 237 | Section 3 -- License Conditions. 238 | 239 | Your exercise of the Licensed Rights is expressly made subject to the 240 | following conditions. 241 | 242 | a. Attribution. 243 | 244 | 1. If You Share the Licensed Material (including in modified 245 | form), You must: 246 | 247 | a. retain the following if it is supplied by the Licensor 248 | with the Licensed Material: 249 | 250 | i. identification of the creator(s) of the Licensed 251 | Material and any others designated to receive 252 | attribution, in any reasonable manner requested by 253 | the Licensor (including by pseudonym if 254 | designated); 255 | 256 | ii. a copyright notice; 257 | 258 | iii. a notice that refers to this Public License; 259 | 260 | iv. a notice that refers to the disclaimer of 261 | warranties; 262 | 263 | v. a URI or hyperlink to the Licensed Material to the 264 | extent reasonably practicable; 265 | 266 | b. indicate if You modified the Licensed Material and 267 | retain an indication of any previous modifications; and 268 | 269 | c. indicate the Licensed Material is licensed under this 270 | Public License, and include the text of, or the URI or 271 | hyperlink to, this Public License. 272 | 273 | 2. You may satisfy the conditions in Section 3(a)(1) in any 274 | reasonable manner based on the medium, means, and context in 275 | which You Share the Licensed Material. For example, it may be 276 | reasonable to satisfy the conditions by providing a URI or 277 | hyperlink to a resource that includes the required 278 | information. 279 | 3. If requested by the Licensor, You must remove any of the 280 | information required by Section 3(a)(1)(A) to the extent 281 | reasonably practicable. 282 | 283 | b. ShareAlike. 284 | 285 | In addition to the conditions in Section 3(a), if You Share 286 | Adapted Material You produce, the following conditions also apply. 287 | 288 | 1. The Adapter's License You apply must be a Creative Commons 289 | license with the same License Elements, this version or 290 | later, or a BY-NC-SA Compatible License. 291 | 292 | 2. You must include the text of, or the URI or hyperlink to, the 293 | Adapter's License You apply. You may satisfy this condition 294 | in any reasonable manner based on the medium, means, and 295 | context in which You Share Adapted Material. 296 | 297 | 3. You may not offer or impose any additional or different terms 298 | or conditions on, or apply any Effective Technological 299 | Measures to, Adapted Material that restrict exercise of the 300 | rights granted under the Adapter's License You apply. 301 | 302 | 303 | Section 4 -- Sui Generis Database Rights. 304 | 305 | Where the Licensed Rights include Sui Generis Database Rights that 306 | apply to Your use of the Licensed Material: 307 | 308 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 309 | to extract, reuse, reproduce, and Share all or a substantial 310 | portion of the contents of the database for NonCommercial purposes 311 | only; 312 | 313 | b. if You include all or a substantial portion of the database 314 | contents in a database in which You have Sui Generis Database 315 | Rights, then the database in which You have Sui Generis Database 316 | Rights (but not its individual contents) is Adapted Material, 317 | including for purposes of Section 3(b); and 318 | 319 | c. You must comply with the conditions in Section 3(a) if You Share 320 | all or a substantial portion of the contents of the database. 321 | 322 | For the avoidance of doubt, this Section 4 supplements and does not 323 | replace Your obligations under this Public License where the Licensed 324 | Rights include other Copyright and Similar Rights. 325 | 326 | 327 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 328 | 329 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 330 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 331 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 332 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 333 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 334 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 335 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 336 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 337 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 338 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 339 | 340 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 341 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 342 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 343 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 344 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 345 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 346 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 347 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 348 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 349 | 350 | c. The disclaimer of warranties and limitation of liability provided 351 | above shall be interpreted in a manner that, to the extent 352 | possible, most closely approximates an absolute disclaimer and 353 | waiver of all liability. 354 | 355 | 356 | Section 6 -- Term and Termination. 357 | 358 | a. This Public License applies for the term of the Copyright and 359 | Similar Rights licensed here. However, if You fail to comply with 360 | this Public License, then Your rights under this Public License 361 | terminate automatically. 362 | 363 | b. Where Your right to use the Licensed Material has terminated under 364 | Section 6(a), it reinstates: 365 | 366 | 1. automatically as of the date the violation is cured, provided 367 | it is cured within 30 days of Your discovery of the 368 | violation; or 369 | 370 | 2. upon express reinstatement by the Licensor. 371 | 372 | For the avoidance of doubt, this Section 6(b) does not affect any 373 | right the Licensor may have to seek remedies for Your violations 374 | of this Public License. 375 | 376 | c. For the avoidance of doubt, the Licensor may also offer the 377 | Licensed Material under separate terms or conditions or stop 378 | distributing the Licensed Material at any time; however, doing so 379 | will not terminate this Public License. 380 | 381 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 382 | License. 383 | 384 | 385 | Section 7 -- Other Terms and Conditions. 386 | 387 | a. The Licensor shall not be bound by any additional or different 388 | terms or conditions communicated by You unless expressly agreed. 389 | 390 | b. Any arrangements, understandings, or agreements regarding the 391 | Licensed Material not stated herein are separate from and 392 | independent of the terms and conditions of this Public License. 393 | 394 | 395 | Section 8 -- Interpretation. 396 | 397 | a. For the avoidance of doubt, this Public License does not, and 398 | shall not be interpreted to, reduce, limit, restrict, or impose 399 | conditions on any use of the Licensed Material that could lawfully 400 | be made without permission under this Public License. 401 | 402 | b. To the extent possible, if any provision of this Public License is 403 | deemed unenforceable, it shall be automatically reformed to the 404 | minimum extent necessary to make it enforceable. If the provision 405 | cannot be reformed, it shall be severed from this Public License 406 | without affecting the enforceability of the remaining terms and 407 | conditions. 408 | 409 | c. No term or condition of this Public License will be waived and no 410 | failure to comply consented to unless expressly agreed to by the 411 | Licensor. 412 | 413 | d. Nothing in this Public License constitutes or may be interpreted 414 | as a limitation upon, or waiver of, any privileges and immunities 415 | that apply to the Licensor or You, including from the legal 416 | processes of any jurisdiction or authority. 417 | 418 | ======================================================================= 419 | 420 | Creative Commons is not a party to its public 421 | licenses. Notwithstanding, Creative Commons may elect to apply one of 422 | its public licenses to material it publishes and in those instances 423 | will be considered the “Licensor.” The text of the Creative Commons 424 | public licenses is dedicated to the public domain under the CC0 Public 425 | Domain Dedication. Except for the limited purpose of indicating that 426 | material is shared under a Creative Commons public license or as 427 | otherwise permitted by the Creative Commons policies published at 428 | creativecommons.org/policies, Creative Commons does not authorize the 429 | use of the trademark "Creative Commons" or any other trademark or logo 430 | of Creative Commons without its prior written consent including, 431 | without limitation, in connection with any unauthorized modifications 432 | to any of its public licenses or any other arrangements, 433 | understandings, or agreements concerning use of licensed material. For 434 | the avoidance of doubt, this paragraph does not form part of the 435 | public licenses. 436 | 437 | Creative Commons may be contacted at creativecommons.org. 438 | --------------------------------------------------------------------------------