diff --git a/slides_sources/old_versions/week-05/presentation-week-05.snm b/.nojekyll similarity index 100% rename from slides_sources/old_versions/week-05/presentation-week-05.snm rename to .nojekyll diff --git a/GeneralNotes/PythonOnWindows.rst b/GeneralNotes/PythonOnWindows.rst deleted file mode 100644 index 1c9889a6..00000000 --- a/GeneralNotes/PythonOnWindows.rst +++ /dev/null @@ -1,276 +0,0 @@ -========================= -Using Python on Windows -========================= - -Python itself is very platform independent. The code you write will be exactlty the same regardless of platform you are running, unless you want to acess specific system services. However, the tools required to install and work with python and associated packages are somewhat different. Also, as Python comes from, and is mostly used by, the FOSS world, many instructions you will find online are *nix oriented, and many packages are set up and tested primarily on Linux and/or OS-X. - -Nevertheless, Python works just fine on Windows once you get yourself properly set up. - -The following are few notes that should help you get running on Windows. - -[NOTE: these notes are oriented to supporting the UWPCE Certificate in Python Programming classes] - -Installing Python -==================== - -There are a number of Python distributions out there, some specifically designed to provide a full featured set of packages, often oreinted to scientific programming. These include: Enthought Canopy, Continuum's Anaconda, and Python(xy). However the prome advantage of these sywtems is getting hard-to-build-and-install scientific packages -- they maynot be as useful for the UW certificate program. So we will recommend a more compact route: - -python.org binaries ---------------------- - -We recommend the binary installer available from python.org: - - - -We are using VErsion 2.7 for this class. Either 32bit or 64bit is fine, although you may have an easier time finding binary packages (see below) for the 32bit version. - -setting up the `PATH` ---------------------------- - -The installer will install to a stardard location, and set itself up in the registry and Start menu. However, for command line use, you will want to put the appropriate locations on your `PATH`. The `PATH` environemnt variable tells the commadn line shell where to look for executables. by adding teh appropriate directory, you can simply type "`python`" on the command line to run python. You will want to add tow directories to the `PATH`:: - - C:\Python27 - C:\Python27\Scripts - -The `Scripts` dir is where Python puts scripts installed by python packages -- ti is very handy to have it on your `PATH` as well. - -Add `";C:\Python27;C:\Python27\Scripts"` (without the quotes) to the end of your DOS path environment variable by following the instructions (these are copied from here: ) - -Instructions - 1. Click on the Windows "Start" button and then click "Control Panel" from the menu that appears. - 2. Click "System" in the Windows control panel, then click "Advanced system settings" to open the "System Properties" dialog box. - - 3. Click the "Environment Variables" button on the "Advanced" tab of the dialog box. - -4. Scroll down in the "System variables" box until you see the "Path" variable. Click on the "Path" entry to highlight, then click the "Edit" button underneath the box. - -5. Add a semicolon to the end of the current path line, which is used as a delimiter, and then type the directory path to add. Click "OK" until all the dialog boxes are closed. - -6. Restart any open command windows to allow the changeto take effect. - -Read more: - -Opening a command Window ("DOS box") --------------------------------------- - a) click Start - b) click Run... - c) type "cmd" (without the quotes) in the text entry field - d) click OK - -"Command line here" ---------------------- -"Command line here" is a utility for the file explorer tht lets you open up a command window already set the the vcurrent directory seen in Windows Explorer. A little googling should find it -- it's very handy. (I think it's built in to Windows 7) - - -Installing Packages -===================== - -While python has a "batteries included" philosphy, and there is a lot of great stuff in the standard library, there will come a time when you'll want to use a thord party package (or many of them...) - -Python packages come (more or less) in three flavors, in order of difficulty to install. - - Pure Python - Packages that contain only python code are pretty easy -- python is very platfrom independt, so the same code runs everywhere, and there is no need for compilation. - - Python and C extension code - Some packages have some modeuls written in C - known as "extansion modules". These modules need to be compiled for the host system before they can be used. - - Python and Extension code with dependencies - Some packages include not jsut C code, but that C code depends on other third party libraries that do not come with the operating system. Some of these are designed specifically to give python users access to a C lib, and some simply need a given lib to due its job. Examples of comonl used C libs: libpng, libcurl, libfreetype, etc. - -distutils ------------ - -The distutils ("distribution utilities") is a pacakge that comes with all recent version of python -- it provides a standrad and robust way to build, install, and distribute packges. IF you encounter a `setup.py` file, you are using distutils. - -Installing from source ------------------------- - -Often you will find a package on the web somewhere, and the develper will provide a zip file or tarball of the package source. In this package, there will most likely be a `setup.py file`. To install the package, you simply run teh command:: - - python setup.py install - -You can also build and install in separate steps:: - - python setup.py build - python setup.py install - -If the package is pure python, this should "just work". However, if the package includes a python extension, it will only work if you have a C compiler installed properly. The best option is Microsoft Visual Studio 2008 (the express addtion is fine, and free). Instaling all that is beyond the scope of this note, but once installed, again, running `setup.py install` should work. - -However, if the package contains a module that depends on a third-party libary, then you need to figure out how to build and install that first -- this is not for teh faint of heart, and not recommended for people without experience building software on Windows. Which brings us to: - - -Installing from binaries --------------------------- - -As many (most) Windows users do not have (nor know how to use) a compiler, and there is now binary pacakge management system for Windows (like apt-get or rpm for Linux), most pacakge maintainers disribute binaries of their packages for Windows. If they don't, there are often third-party binary packages available. IN this case, they are almost always built for the versions of python available from `python.org`. - -At the web site for the pacakge of interest, look for a binary installer (usually a MSI installer). Make sure it is for the python version (2.7) you are running, and (very important!) the bit-depth of your python (32 or 64 bit). For example, wxPython has the following binaries available:: - - wxPython2.9-win32-py26 32-bit Python 2.6 - wxPython2.9-win64-py26 64-bit Python 2.6 - wxPython2.9-win32-py27 32-bit Python 2.7 - wxPython2.9-win64-py27 64-bit Python 2.7 - -Make sure you download the correct version, or you will get a cryptic error message. - -Once you get it, you can point-and-click install it and you should be good to go. - -Binary Repositories ---------------------- - -There are few repositories of Windows binary pacakges that may have what you are looking for. Msot notable is the repository maintained by Christoph Gohlke: . This is an outstanding resource -- a really remarkable collectin of up to date packages for Windows. Again, be sure to download the version that matches your python installation. - - -`pip` and `easy_install` -========================== - -`pip` and `easy_install` are systems that seek to automatically find a package you are looking for in the python package index (pypi: https://pypi.python.org/pypi) and install them for you. They work great on all systems for pure-python pacakges, but often fail with more complex packages. To install a package:: - - pip install package_name - -as easy as that. `pip` and 'easy_install` also track pacakge dependencies, and try to install them for you as well. It's great when it works. - -installing `pip` ---------------- - -Installing `pip` requires a bit of a "bootstrap" process. First you need to install `setuptools`:. To isntall setuptools, look for the `ez_setup.py` on the setuptools page, download it, and run it:: - - python ez_setup.py - -That should install the latest setuptools. Once that's done, you should be able install pip with easy_install:: - - easy_install pip - -whew! that was harder than it should be. - - - -2. Add ";C:\Python27;C:\Python27\Scripts" (without the quotes) to the end of your DOS path environment variable. For instructions try: - http://www.ehow.com/how_7781683_add-path.html - -Note: if you already have a cmd window open, you'll need to close and re-open it after doing step 2. - -3. Open a cmd window: - a) click Start - b) click Run... - c) type "cmd" (without the quotes) in the text entry field - d) click OK - -4. In the cmd window type: "easy_install swampy" (without the quotes). - - -And two more steps to get iPython and pyreadline: - -5. In the cmd window type: "easy_install iPython" (without the quotes). - -6. In the cmd window type: "easy_install pyreadline" (without the quotes). - - - -- - - - - - - - - - - - Step 4. should look like this: - - - - - - - - - - - - - - -Microsoft Windows XP [Version 5.1.2600] -(C) Copyright 1985-2001 Microsoft Corp. - -C:\Python27>easy_install swampy -Searching for swampy -Reading http://pypi.python.org/simple/swampy/ -Reading http://allendowney.com/swampy -Best match: swampy 2.1.1 -Downloading http://pypi.python.org/packages/source/s/swampy/swampy-2.1.1.tar.gz# -md5=a302348a849da33cb454fde993fb9757 -Processing swampy-2.1.1.tar.gz -Running swampy-2.1.1\setup.py -q bdist_egg --dist-dir c:\docume~1\daniel\locals~ -1\temp\easy_install-q4vdfv\swampy-2.1.1\egg-dist-tmp-gh3rvr -zip_safe flag not set; analyzing archive contents... -swampy.Lumpy: module MAY be using inspect.stack -Adding swampy 2.1.1 to easy-install.pth file - -Installed c:\python27\lib\site-packages\swampy-2.1.1-py2.7.egg -Processing dependencies for swampy -Finished processing dependencies for swampy - - - -- - - - - - - - - - - - Step 5. should look like this: - - - - - - - - - - - - - - -Microsoft Windows XP [Version 5.1.2600] -(C) Copyright 1985-2001 Microsoft Corp. - -C:\Documents and Settings\Daniel>easy_install iPython -Searching for iPython -Reading http://pypi.python.org/simple/iPython/ -Reading http://ipython.scipy.org -Reading http://ipython.scipy.org/dist -Reading http://ipython.scipy.org/dist/0.8.4 -Reading http://ipython.scipy.org/dist/0.9.1 -Reading http://ipython.org -Reading http://archive.ipython.org/release/0.12.1 -Reading https://github.com/ipython/ipython/downloads -Reading http://ipython.scipy.org/dist/old/0.9 -Reading http://ipython.scipy.org/dist/0.10 -Reading http://archive.ipython.org/release/0.11/ -Reading http://archive.ipython.org/release/0.12 -Best match: ipython 0.13 -Downloading http://pypi.python.org/packages/2.7/i/ipython/ipython-0.13-py2.7.egg -#md5=694ce5981bf163922bd09617a4742a61 -Processing ipython-0.13-py2.7.egg -creating c:\python27\lib\site-packages\ipython-0.13-py2.7.egg -Extracting ipython-0.13-py2.7.egg to c:\python27\lib\site-packages -Adding ipython 0.13 to easy-install.pth file -Installing ipcontroller-script.py script to C:\Python27\Scripts -Installing ipcontroller.exe script to C:\Python27\Scripts -Installing ipcontroller.exe.manifest script to C:\Python27\Scripts -Installing iptest-script.py script to C:\Python27\Scripts -Installing iptest.exe script to C:\Python27\Scripts -Installing iptest.exe.manifest script to C:\Python27\Scripts -Installing ipcluster-script.py script to C:\Python27\Scripts -Installing ipcluster.exe script to C:\Python27\Scripts -Installing ipcluster.exe.manifest script to C:\Python27\Scripts -Installing ipython-script.py script to C:\Python27\Scripts -Installing ipython.exe script to C:\Python27\Scripts -Installing ipython.exe.manifest script to C:\Python27\Scripts -Installing pycolor-script.py script to C:\Python27\Scripts -Installing pycolor.exe script to C:\Python27\Scripts -Installing pycolor.exe.manifest script to C:\Python27\Scripts -Installing iplogger-script.py script to C:\Python27\Scripts -Installing iplogger.exe script to C:\Python27\Scripts -Installing iplogger.exe.manifest script to C:\Python27\Scripts -Installing irunner-script.py script to C:\Python27\Scripts -Installing irunner.exe script to C:\Python27\Scripts -Installing irunner.exe.manifest script to C:\Python27\Scripts -Installing ipengine-script.py script to C:\Python27\Scripts -Installing ipengine.exe script to C:\Python27\Scripts -Installing ipengine.exe.manifest script to C:\Python27\Scripts - -Installed c:\python27\lib\site-packages\ipython-0.13-py2.7.egg -Processing dependencies for iPython -Finished processing dependencies for iPython - - - -- - - - - - - - - - - - Step 6. should look like this: - - - - - - - - - - - - - - -Microsoft Windows XP [Version 5.1.2600] -(C) Copyright 1985-2001 Microsoft Corp. - -C:\Documents and Settings\Daniel>easy_install pyreadline -Searching for pyreadline -Reading http://pypi.python.org/simple/pyreadline/ -Reading http://ipython.scipy.org/moin/PyReadline/Intro -Reading https://launchpad.net/pyreadline/+download -Reading http://projects.scipy.org/ipython/ipython/wiki/PyReadline/Intro -Best match: pyreadline 2.0-dev1 -Downloading https://launchpad.net/pyreadline/2.0/pyreadline-2.0-prerelease/+down -load/pyreadline-2.0-dev1.win32.exe -Processing pyreadline-2.0-dev1.win32.exe -creating 'c:\docume~1\daniel\locals~1\temp\easy_install-ndbace\pyreadline-2.0_de -v1-py2.7-win32.egg' and adding 'c:\docume~1\daniel\locals~1\temp\easy_install-nd -bace\pyreadline-2.0_dev1-py2.7-win32.egg.tmp' to it -Moving pyreadline-2.0_dev1-py2.7-win32.egg to c:\python27\lib\site-packages -Adding pyreadline 2.0-dev1 to easy-install.pth file - -Installed c:\python27\lib\site-packages\pyreadline-2.0_dev1-py2.7-win32.egg -Processing dependencies for pyreadline -Finished processing dependencies for pyreadline \ No newline at end of file diff --git a/GeneralNotes/iPythonForWindows.rst b/GeneralNotes/iPythonForWindows.rst deleted file mode 100644 index afc93590..00000000 --- a/GeneralNotes/iPythonForWindows.rst +++ /dev/null @@ -1,69 +0,0 @@ -Installing and Running IPython for Windows: -############################### - -It turns out that iPython works best when there are few other packages installed that it depends on, so it'snot quite as easy as simply instaling the one package. - -these re some note put together by Dick Smith -- as he took the time to figure it out, We asked him to write up these notes: - - -Preconditions: -=================== - -(see: https://github.com/UWPCE-PythonCert/IntroToPython/blob/master/GeneralNotes/PythonOnWindows.rst for more detail) - -Python Interpreter: --------------------- -32 or 64 bit version of Python for Windows 2.7 installed in C:\Python27\ -(the version found at python.org) - -PATH set: -------------- -MyComputer -> Properties -> Advanced System Settings -> System Variables -set up appropriately to modify PATH or path and create PYTHONPATH, -per install instructions., - -Getting packages: -=================== -Use your web browser to navigate to this URL for downloadable -Python Windows extension installers recommended by the instructor: - -"Unofficial Windows Binaries for Python Extension Packages -by Christoph Gohlke, Laboratory for Fluorescence Dynamics, -University of California, Irvine". - -http://www.lfd.uci.edu/~gohlke/pythonlibs/ - -This is not a Git repository. These are Windows-executable installers -which should be pulled to your PC's download directory. - -Single-clicking will start the download process, then executed with a double-click. - -NOTE: This repository containt both 32bit and 64bit pacakges -- make sure to get the ones that match the python installed. - -Download and run these three installers, in this order: - -SetupTools: -- Required by the IPython install script. - -setuptools-1.1.6.win32-py2.7.exe - -PyReadline: -- Windows extension for adding color (and other nifty features) to the interactive -presentation. - -pyreadline-2.0.win32-py2.7.exe - -IPython itself: - -ipython-1.1.0.win32-py2.7.exe - -Run it by double-clicking on ``C:\Python27\Scripts\ipython.exe`` - -or typing ``ipython`` on the command line (DOS box) - -I recommend making a desktop shortcut and putting that in the target line. - -It brings up a commandline console with some initial text about -resources available via commands, and the Ipython prompt:: - - IN [1]: - - diff --git a/README.md b/README.md new file mode 100644 index 00000000..6320f591 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +IntroToPython gh-pages branch +=============================== + +This branch holds the genreated html version of the docs for the +Introduction to Python: First in the Python Certification series class. + +It is here so that the rendered version can be served by github. + +To see it -- go to: + +http://UWPCE-PythonCert.github.io/IntroToPython + + diff --git a/README.rst b/README.rst deleted file mode 100644 index 37ad4a54..00000000 --- a/README.rst +++ /dev/null @@ -1,10 +0,0 @@ -IntroToPython -============== - -Introduction to Python: First in the Python Certification series. - -This repository contains the source materials for the first class in the the University of Washington Professional and Continuing Education Program Python Certification Program: - -.. _Certificate in Python Programming : http://www.pce.uw.edu/certificates/python-programming.html - -See the Syllabus for more detail, and the individual class notes for the instructional material itself. \ No newline at end of file diff --git a/Syllabus.rst b/Syllabus.rst deleted file mode 100644 index 9e4ff116..00000000 --- a/Syllabus.rst +++ /dev/null @@ -1,232 +0,0 @@ -************************************ -Syllabus: Introduction to Python -************************************ - -UW Adult and Continuing Education Program -============================================ - -Certification in Python Programming ---------------------------------------------------- - -Tuesdays 6-9 pm: Sept 30 - Dec 9, 2014 (10 Sessions) -..................................................... - - -NOTE: in the spirit of the dynamic nature of Python, the Syllabus (and the class) will be a dynamic document -- evolving as the class progresses. The general structure is fixed, but the details will change. - - -Instructor: -=============== -Christopher Barker, PhD. (``PythonCHB@gmail.com``) is an oceanographer and software developer currently working for NOAA in Seattle. He first began programming over 30 years ago, and has been using programming to solve problems in science and engineering ever since. He has been using Python as his primary language since 1998. Chris gives numerous presentations on his work at professional conferences, and teaches oceanography and oil spill modeling at regular workshops. He has been involved with the Seattle Python Interest Group (www.seapig.org) for many years, and has given a number of talks and tutorials at SEAPIG meetings, as well as the PyCon and Scipy conferences. He is an active participant in a number Python-related open source communities, and has served as a Google Summer of Code mentor for the wxPython project. - - -Python Version: -=============== - -There are two main supported versions of Python: the 2.* series and the 3.* series (py3k). In this class we will be using "cPython" version 2.7, the version distributed by ``_. Each student is expected to have access to a computer with python 2.7 and a decent programmers text editor installed, both during class and for homework assignments. Any modern Operating sytem is fine: OS-X, Linux, or Windows. - -Approach: -========= -This class assumes a basic knowledge of programming. Thus I will try to emphasize what is unique about Python, with less focus on general programing concepts. - -One learns programming by doing -- I'll be demonstrating as I talk about concepts, and I will pause frequently to give you a chance to try things out, so plan on having a laptop up and running with python and your text editor of choice during each class. - -Homework: -========= -There will generally be weekly homework assignments. They will usually be flexible to allow for students' varying time constraints. However, you learn by doing, so I do encourage you to put some time in to the homework. I will review your work if you ask me to, and do a mini code-review of selected assignments during class. - -`Teach Yourself Programming in Ten Years `_ - -In addition, I will ask each student to identify a small project, ideally related to your work, that you can develop as a class project -- that project will be the primary homework for the last few classes. - -Lightning Talks: ------------------ - -Each student is expected to give one "lightning talk" during the class -- this is a simple 5-minute talk on something related to Python -- totally up to you. We will randomly assign the talks schedule (using Python, of course) during the first class. - -Class format: -============== - -Each class will be broken down something like this: - -- 30 minutes talk -- 25 minutes lab time - -- 5 minute lightning talk -- 5 minute lightning talk -- 20 minutes talk -- 30 minutes lab time - -- 5 minute lightning talk -- 5 minute lightning talk -- 20 minutes talk -- 30 minutes lab time - -(there will be no official breaks, but we should all feel free to move about during lab/exercise time) - - -gitHub: -======= - -All class materials will be up on gitHub (where you probably found this). This allows me to update things at the last minute, and the students can all have easy access to the latest versions. It also familiarizes you with a very useful tool for software development. We'll spend a bit of time during the first class getting everyone up and running with git.... - -_ - -for rendered and ready to read version: - - - -Reading: -======== - -There is no assigned text book. However, you may find it beneficial to read other discussions of topics in addition to what I present in class: either to explore a topic more deeply, or to simple get another viewpoint. There are many good books on Python, and many more excellent discussions of individual topics on the web. A few you may want to consider: - - - -References for getting started -------------------------------- - -* **The Python Tutorial** - (https://docs.python.org/2/tutorial/): This is the - official tutorial from the Python website. No more authoritative source is - available. - -* **Code Academy Python Track** - (http://www.codecademy.com/tracks/python): Often - cited as a great resource, this site offers an entertaining and engaging - approach and in-browser work. - -* **Learn Python the Hard Way** - (http://learnpythonthehardway.org/book/): Solid - and gradual. This course offers a great foundation for folks who have never - programmed in any language before. - -* **Dive Into Python 3** - (http://www.diveinto.org/python3/): The updated version - of a classic. This book offers an introduction to Python aimed at the student - who has experience programming in another language. - -* **Python for You and Me** - (http://pymbook.readthedocs.org/en/latest/): Simple - and clear. This is a great book for absolute newcomers, or to keep as a quick - reference as you get used to the language. - -* **Think Python** - (http://greenteapress.com/thinkpython/): Methodical and - complete. This book offers a very "computer science"-style introduction to - Python. It is really an intro to Python *in the service of* Computer Science, - though, so while helpful for the absolute newcomer, it isn't quite as - "pythonic" as it might be. - -* **Core Python Programming** - (http://corepython.com/): Only available as a dead - trees version, but if you like to have book to hold in your hands anyway, this - is the best textbook style introduction out there. It starts from the - beginning, but gets into the full language. Published in 2009, but still in - print, with updated appendixes available for new language features. - -* **Python 101** - (http://www.blog.pythonlibrary.org/2014/06/03/python-101-book-published-today/) - Available as a reasonably priced ebook. This is a new one from a popular Blogger - about Python. Lots of practical examples. Also avaiable as a Kindle book: - http://www.amazon.com/Python-101-Michael-Driscoll-ebook/dp/B00KQTFHNK - -* **Python Essential Reference** - (http://www.dabeaz.com/per.html) - The definitive reference for both Python and much of the standard library. - - -... and many others - -Class Schedule: -================ - -Topics of each week --------------------- - -Week 1: Sept 30 -................ - -General Introduction to Python and the class. Using the command interpreter and development environment. -Finding and using the documentation. Getting help. Class github project. Basic data types, functions. - - -Week 2: Oct 7 -................ - -More on functions: definition and use, arguments, block structure, scope, recursion - -Modules and import - -Conditionals and Boolean expressions - - -Week 3: Oct 14 -................. - -Sequences: Strings, Tuples, Lists - -Iteration, Looping and control flow. - -String methods and formatting - - -Week 4: Oct 21 -................ - -Dictionaries, Sets and Mutability. - -Exceptions. - -Files and Text Processing - - -Week 5: Oct 28 -........................ - -Unicode. - -Advanced Argument passing - -List and Dict Comprehensions - -Testing - -Week 6: November 4 -.................... - -Lambda and Functional programming. - -Object oriented programming. Classes, instances, and methods - - -Week 7: November 11 -....................... - -More OO -- Inheritance and duck typing - - -Week 8: November 18 -.................... - -More OO: Special methods - -Iterators and Generators - - -Week 9: December 2 -................... - -Decorators - -Context Managers - -Packages and packaging - - -Week 10: December 9 -.................... - -Persistence / Serialization - - diff --git a/slides_sources/source/supplements/ICanEatGlass.utf16.txt b/_downloads/ICanEatGlass.utf16.txt similarity index 100% rename from slides_sources/source/supplements/ICanEatGlass.utf16.txt rename to _downloads/ICanEatGlass.utf16.txt diff --git a/_downloads/ICanEatGlass.utf161.txt b/_downloads/ICanEatGlass.utf161.txt new file mode 100644 index 00000000..24a0858d Binary files /dev/null and b/_downloads/ICanEatGlass.utf161.txt differ diff --git a/slides_sources/source/supplements/ICanEatGlass.utf8.txt b/_downloads/ICanEatGlass.utf8.txt similarity index 100% rename from slides_sources/source/supplements/ICanEatGlass.utf8.txt rename to _downloads/ICanEatGlass.utf8.txt diff --git a/_downloads/ICanEatGlass.utf81.txt b/_downloads/ICanEatGlass.utf81.txt new file mode 100644 index 00000000..9ecba2b9 --- /dev/null +++ b/_downloads/ICanEatGlass.utf81.txt @@ -0,0 +1,23 @@ +I Can Eat Glass: + +And from the sublime to the ridiculous, here is a certain phrase in an assortment of languages: + +Sanskrit: काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम् ॥ + +Sanskrit (standard transcription): kācaṃ śaknomyattum; nopahinasti mām. + +Classical Greek: ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει. + +Greek (monotonic): Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. + +Greek (polytonic): Μπορῶ νὰ φάω σπασμένα γυαλιὰ χωρὶς νὰ πάθω τίποτα. + +Latin: Vitrum edere possum; mihi non nocet. + +Old French: Je puis mangier del voirre. Ne me nuit. + +French: Je peux manger du verre, ça ne me fait pas mal. + +Provençal / Occitan: Pòdi manjar de veire, me nafrariá pas. + +Québécois: J'peux manger d'la vitre, ça m'fa pas mal. \ No newline at end of file diff --git a/_downloads/__pycache__/test_generator.cpython-35-PYTEST.pyc b/_downloads/__pycache__/test_generator.cpython-35-PYTEST.pyc new file mode 100644 index 00000000..635ed9e4 Binary files /dev/null and b/_downloads/__pycache__/test_generator.cpython-35-PYTEST.pyc differ diff --git a/_downloads/__pycache__/test_p_wrapper.cpython-35-PYTEST.pyc b/_downloads/__pycache__/test_p_wrapper.cpython-35-PYTEST.pyc new file mode 100644 index 00000000..cac5a510 Binary files /dev/null and b/_downloads/__pycache__/test_p_wrapper.cpython-35-PYTEST.pyc differ diff --git a/_downloads/class_method.py b/_downloads/class_method.py new file mode 100644 index 00000000..93fba91f --- /dev/null +++ b/_downloads/class_method.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +""" +example of a class method +""" + + +class C: + def __init__(self, x, y): + self.x = x + self.y = y + + @classmethod + def a_class_method(cls, y): + print("in a_class_method", cls) + return cls(y, y**2) + + +class C2(C): + pass + + +if __name__ == "__main__": + + c = C(3, 4) + print(type(c), c.x, c.y) + + c2 = C.a_class_method(3) + print(type(c2), c2.x, c2.y) + + c3 = c2.a_class_method(2) + print(type(c3), c3.x, c3.y) diff --git a/_downloads/context_managers.py b/_downloads/context_managers.py new file mode 100644 index 00000000..ecf3ee54 --- /dev/null +++ b/_downloads/context_managers.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +import sys +from io import StringIO +from contextlib import contextmanager + + +class Context(object): + """from Doug Hellmann, PyMOTW + http://pymotw.com/2/contextlib/#module-contextlib + """ + def __init__(self, handle_error): + print('__init__({})'.format(handle_error)) + self.handle_error = handle_error + + def __enter__(self): + print('__enter__()') + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + print('__exit__({}, {}, {})'.format(exc_type, exc_val, exc_tb)) + if exc_type == ZeroDivisionError: + return True + else: + return False + +# return self.handle_error + +@contextmanager +def context(boolean): + print("__init__ code here") + try: + print("__enter__ code goes here") + yield object() + except Exception as e: + print("errors handled here") + if not boolean: + raise e + finally: + print("__exit__ cleanup goes here") + + +@contextmanager +def print_encoded(encoding): + old_stdout = sys.stdout + sys.stdout = buff = StringIO() + try: + yield None + finally: + sys.stdout = old_stdout + buff.seek(0) + raw = buff.read() + encoded = raw.encode(encoding) + print(encoded) diff --git a/slides_sources/source/supplements/exception_test.py b/_downloads/exception_test.py old mode 100755 new mode 100644 similarity index 100% rename from slides_sources/source/supplements/exception_test.py rename to _downloads/exception_test.py diff --git a/slides_sources/source/supplements/hello_unicode.py b/_downloads/hello_unicode.py similarity index 100% rename from slides_sources/source/supplements/hello_unicode.py rename to _downloads/hello_unicode.py diff --git a/slides_sources/old_versions/week-05/code/hello_unicode.py b/_downloads/hello_unicode1.py similarity index 92% rename from slides_sources/old_versions/week-05/code/hello_unicode.py rename to _downloads/hello_unicode1.py index fce28660..6bbad1de 100644 --- a/slides_sources/old_versions/week-05/code/hello_unicode.py +++ b/_downloads/hello_unicode1.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # -*- coding: utf-8 -*- hello = 'Hello ' diff --git a/slides_sources/old_versions/week-08/code/iterator_1.py b/_downloads/iterator_1.py similarity index 84% rename from slides_sources/old_versions/week-08/code/iterator_1.py rename to _downloads/iterator_1.py index 4cb3fa80..6cc9231c 100644 --- a/slides_sources/old_versions/week-08/code/iterator_1.py +++ b/_downloads/iterator_1.py @@ -10,23 +10,23 @@ class IterateMe_1(object): About as simple an iterator as you can get: returns the sequence of numbers from zero to 4 - ( like xrange(4) ) + ( like range(4) ) """ def __init__(self, stop=5): self.current = -1 self.stop = stop def __iter__(self): return self - def next(self): + def __next__(self): self.current += 1 if self.current < self.stop: return self.current else: raise StopIteration - + if __name__ == "__main__": - - print "first version" + + print("Testing the iterator") for i in IterateMe_1(): - print i + print(i) diff --git a/slides_sources/source/supplements/latin1_test.py b/_downloads/latin1_test.py similarity index 100% rename from slides_sources/source/supplements/latin1_test.py rename to _downloads/latin1_test.py diff --git a/_downloads/latin1_test1.py b/_downloads/latin1_test1.py new file mode 100644 index 00000000..3990078f --- /dev/null +++ b/_downloads/latin1_test1.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +""" +An example of using latin-1 as a universal encoding + +latin-1 is a superset of ASCII that is suitable for western european languages. + +Is the most common, and a good default, if you need a one-byte per char encoding +for European text. + +It also has a nice property: + : every byte value from 0 to 255 is avalid charactor + +Thus you will never get an UnicodeDecodeError if +you try to decode arbitrary bytes with latin-1. + +And it can "round-trip" trhough a unicode object. + +This can be useful is you don't know the encoding -- at least it won't break. +It's also useful if you need to work with cobined text+binary data. + + + +""" + +# all the byte values in a bytes (str) object: +all_bytes = ''.join( [chr(i) for i in range(255)] ) + +print type(all_bytes) +print len(all_bytes) + +print "Example value: 20" +print ord(all_bytes[20]) == 20 +print "Example high value: 245" +print ord(all_bytes[245]) == 245 + +# now decode it to a unicode object: +try: + uni = all_bytes.decode() +except UnicodeDecodeError: + print "OOPS: can't decode with default encoding" + +# latin-1 works: +try: + all_uni = all_bytes.decode('latin-1') + print "Yup -- that worked" + print all_uni + print "note that the ASCII subset is the same..." +except UnicodeDecodeError: + print "OOPS: This should have worked!!" + raise + +## now show that it round-trips: +all_bytes2 = all_uni.encode('latin-1') + +if all_bytes2 == all_bytes: + print "yup -- that worked...the values are preserved on the round trip." +else: + print "Hey, that should have worked" + + + + + + + diff --git a/_downloads/my_for.py b/_downloads/my_for.py new file mode 100644 index 00000000..6023ad9f --- /dev/null +++ b/_downloads/my_for.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +""" +hand writing 'for' + +demonstrates how for interacts with an iterable +""" + + +l = [1,2,3,4,5,] + + +def my_for(an_iterable, func): + """ + Emulation of a for loop. + + func() will be called with each item in an_iterable + + :param an_iterable: anything that satisfies the interation protocol + + :param func: a callable -- it will be called, passing in each item + in an_iterable. + + """ + # equiv of "for i in l:" + iterator = iter(an_iterable) + while True: + try: + i = next(iterator) + except StopIteration: + break + func(i) + + +if __name__ == "__main__": + + def print_func(x): + print(x) + + l = [1,2,3,4,5,] + my_for(l, print_func) + + t = ('a','b','c','d') + + my_for(t, print_func) + + + + + diff --git a/_downloads/properties_example.py b/_downloads/properties_example.py new file mode 100644 index 00000000..f70760e9 --- /dev/null +++ b/_downloads/properties_example.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +""" +Example code for properties + +NOTE: if your getters and setters are this simple: don't do this! + +""" + + +class C: + def __init__(self): + self._x = None + @property + def x(self): + print("in getter") + return self._x + @x.setter + def x(self, value): + print("in setter", value) + self._x = value + @x.deleter + def x(self): + del self._x + +if __name__ == "__main__": + c = C() + c.x = 5 + print(c.x) + diff --git a/_downloads/property_ugly.py b/_downloads/property_ugly.py new file mode 100644 index 00000000..d20c1dcc --- /dev/null +++ b/_downloads/property_ugly.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +class C(object): + """ + Property defined in about the most ugly way possible + """ + def __init__(self): + self._x = None + def x(self): + return self._x + x = property(x) + def _set_x(self, value): + self._x = value + x = x.setter(_set_x) + def _del_x(self): + del self._x + x = x.deleter(_del_x) + + diff --git a/slides_sources/source/homework/sample_html.html b/_downloads/sample_html.html similarity index 100% rename from slides_sources/source/homework/sample_html.html rename to _downloads/sample_html.html diff --git a/slides_sources/old_versions/week-04/homework/sherlock.txt b/_downloads/sherlock.txt similarity index 100% rename from slides_sources/old_versions/week-04/homework/sherlock.txt rename to _downloads/sherlock.txt diff --git a/slides_sources/source/homework/sherlock.txt b/_downloads/sherlock1.txt similarity index 100% rename from slides_sources/source/homework/sherlock.txt rename to _downloads/sherlock1.txt diff --git a/slides_sources/old_versions/week-04/homework/sherlock_small.txt b/_downloads/sherlock_small.txt similarity index 98% rename from slides_sources/old_versions/week-04/homework/sherlock_small.txt rename to _downloads/sherlock_small.txt index 992a29b1..dcccaabd 100644 --- a/slides_sources/old_versions/week-04/homework/sherlock_small.txt +++ b/_downloads/sherlock_small.txt @@ -14,3 +14,4 @@ own story. He was at work again. He had risen out of his drug-created dreams and was hot upon the scent of some new problem. I rang the bell and was shown up to the chamber which had formerly been in part my own. + diff --git a/_downloads/static_method.py b/_downloads/static_method.py new file mode 100644 index 00000000..ce476ab0 --- /dev/null +++ b/_downloads/static_method.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +""" +examples of a static methods +""" + + +class C: + + @staticmethod + def a_static_method(a, b): + print "in a_static_method" + return a+b + + def test(self): + return self.a_static_method(2, 3) + +# if __name__ == "__main__": + +# print C.a_static_method(3,4) + +# c = C() + +# print c.a_static_method(4,5) + +# print c.test() diff --git a/_downloads/test_generator.py b/_downloads/test_generator.py new file mode 100644 index 00000000..d88255f7 --- /dev/null +++ b/_downloads/test_generator.py @@ -0,0 +1,78 @@ +""" +test_generator.py + +tests the solution to the generator lab + +can be run with py.test or nosetests +""" + +import generator_solution as gen + + +def test_intsum(): + + g = gen.intsum() + + assert next(g) == 0 + assert next(g) == 1 + assert next(g) == 3 + assert next(g) == 6 + assert next(g) == 10 + assert next(g) == 15 + + +def test_intsum2(): + + g = gen.intsum2() + + assert next(g) == 0 + assert next(g) == 1 + assert next(g) == 3 + assert next(g) == 6 + assert next(g) == 10 + assert next(g) == 15 + + +def test_doubler(): + + g = gen.doubler() + + assert next(g) == 1 + assert next(g) == 2 + assert next(g) == 4 + assert next(g) == 8 + assert next(g) == 16 + assert next(g) == 32 + + for i in range(10): + j = next(g) + + assert j == 2**15 + + +def test_fib(): + g = gen.fib() + + assert next(g) == 1 + assert next(g) == 1 + assert next(g) == 2 + assert next(g) == 3 + assert next(g) == 5 + assert next(g) == 8 + assert next(g) == 13 + assert next(g) == 21 + + +def test_prime(): + g = gen.prime() + + assert next(g) == 2 + assert next(g) == 3 + assert next(g) == 5 + assert next(g) == 7 + assert next(g) == 11 + assert next(g) == 13 + assert next(g) == 17 + assert next(g) == 19 + assert next(g) == 23 + diff --git a/_downloads/test_p_wrapper.py b/_downloads/test_p_wrapper.py new file mode 100644 index 00000000..40ba0fde --- /dev/null +++ b/_downloads/test_p_wrapper.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +test code for the p_wrapper assignment +""" + +from p_wrapper import p_wrapper #, tag_wrapper + + +def test_p_wrapper(): + @p_wrapper + def return_a_string(string): + return string + + assert return_a_string('this is a string') == '

this is a string

' + +def test_with_args(): + @p_wrapper + def f_string(a, b, this=45 ): + return "the numbers are: {}, {}, {}".format(a,b,this) + + assert f_string(2, 3, this=54) == "

the numbers are: 2, 3, 54

" + + +#Extra credit: + +def test_tag_wrapper(): + @tag_wrapper('html') + def return_a_string(string): + return string + + assert return_a_string("this is a string") == " this is a string " + +def test_tag_wrapper2(): + @tag_wrapper('div') + def return_a_string(string): + return string + + assert return_a_string("this is a string") == "
this is a string
" diff --git a/slides_sources/source/supplements/text.utf16 b/_downloads/text.utf16 similarity index 100% rename from slides_sources/source/supplements/text.utf16 rename to _downloads/text.utf16 diff --git a/slides_sources/source/supplements/text.utf32 b/_downloads/text.utf32 similarity index 100% rename from slides_sources/source/supplements/text.utf32 rename to _downloads/text.utf32 diff --git a/slides_sources/source/supplements/text.utf8 b/_downloads/text.utf8 similarity index 100% rename from slides_sources/source/supplements/text.utf8 rename to _downloads/text.utf8 diff --git a/_downloads/text1.utf16 b/_downloads/text1.utf16 new file mode 100644 index 00000000..b80b2efc Binary files /dev/null and b/_downloads/text1.utf16 differ diff --git a/_downloads/text1.utf32 b/_downloads/text1.utf32 new file mode 100644 index 00000000..c5295310 Binary files /dev/null and b/_downloads/text1.utf32 differ diff --git a/_downloads/text1.utf8 b/_downloads/text1.utf8 new file mode 100644 index 00000000..9de18890 --- /dev/null +++ b/_downloads/text1.utf8 @@ -0,0 +1,17 @@ +Origin (in native language) Name (in native language) +Հայաստան Արամ Խաչատրյան + Australia Nicole Kidman + Österreich Johann Strauß + Azərbaycan Vaqif Səmədoğlu + Азәрбајҹан Вагиф Сәмәдоғлу + Azərbaycan Heydər Əliyev + Азәрбајҹан Һејдәр Әлијев + België René Magritte + Belgique René Magritte + Belgien René Magritte + বাংলা সুকুমার রায় + འབྲུག་ཡུལ། མགོན་པོ་རྡོ་རྗེ། + ប្រទេស​​​កម្ពុជា ព្រះ​ពុទ្ឋឃោសាចារ‌្យ​ជួន​ណាត +Canada Céline Dion + ᓄᓇᕗᒻᒥᐅᑦ ᓱᓴᓐ ᐊᒡᓗᒃᑲᖅ + \ No newline at end of file diff --git a/_downloads/unicode_exception_test.py b/_downloads/unicode_exception_test.py new file mode 100644 index 00000000..24666dc2 --- /dev/null +++ b/_downloads/unicode_exception_test.py @@ -0,0 +1,16 @@ +#!/usr/bin/python + +""" +example for what happens when you pass non-ascii unicode to a Exception +""" + +#msg = u'This is an ASCII-compatible unicode message' + +msg = u'This is an non ASCII\N{EM DASH}compatible unicode message' + +print "\nDo you see this message in the Exception report?\n" +print msg +print + +raise ValueError(msg) + diff --git a/slides_sources/source/supplements/unicodify.py b/_downloads/unicodify.py similarity index 100% rename from slides_sources/source/supplements/unicodify.py rename to _downloads/unicodify.py diff --git a/_downloads/unicodify1.py b/_downloads/unicodify1.py new file mode 100644 index 00000000..15683ee6 --- /dev/null +++ b/_downloads/unicodify1.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +''' +Decorators to convert all arguments passed to a function or method to +unicode or str, including default arguments + +From: http://axialcorps.com/2014/03/20/unicode-str/ + +''' + + +import sys +import functools +import inspect + +def _convert_arg(arg, from_, conv, enc): + '''Safely convert unicode to string or string to unicode''' + return getattr(arg, conv)(encoding=enc) if isinstance(arg, from_) else arg + +def _wrap_convert(from_type, fn, encoding=None): + '''Decorate a function converting all str arguments to unicode or + vice-versa''' + conv = 'decode' if from_type is str else 'encode' + encoding = encoding or sys.getdefaultencoding() + + # override string defaults using partial + aspec, dflts = inspect.getargspec(fn), {} + if aspec.defaults: + for k,v in zip(aspec.args[-len(aspec.defaults):],aspec.defaults): + dflts[k] = _convert_arg(v, from_type, conv, encoding) + fn = functools.partial(fn, **dflts) + + @functools.wraps(fn.func if isinstance(fn, functools.partial) else fn) + def converted(*args, **kwargs): + args = [_convert_arg(a, from_type, conv, encoding) for a in args] + for k,v in kwargs.iteritems(): + kwargs[k] = _convert_arg(v, from_type, conv, encoding) + return fn(*args, **kwargs) + + return converted + +def unicodify(fn=None, encoding=None): + '''Convert all str arguments to unicode''' + if fn is None: + return functools.partial(unicodify, encoding=encoding) + return _wrap_convert(str, fn, encoding=encoding) + +def stringify(fn=None, encoding=None): + '''Convert all unicode arguments to str''' + if fn is None: + return functools.partial(stringify, encoding=encoding) + return _wrap_convert(unicode, fn, encoding=encoding) + +__all__ = ['unicodify', 'stringify'] \ No newline at end of file diff --git a/_downloads/vector.py b/_downloads/vector.py new file mode 100644 index 00000000..8d9e2eac --- /dev/null +++ b/_downloads/vector.py @@ -0,0 +1,47 @@ +""" +Vector type with +, * redefined as Vector addition and dot product +From Jon Jacky's Intro to Python course: + http://staff.washington.edu/jon/python-course/ +""" + + +class Vector(list): + def __repr__(self): + """ + String representation, uses list (superclass) representation + """ + return 'Vector(%s)' % super(Vector, self).__repr__() + + def __add__(self, v): + """ + redefine + as element-wise Vector sum + """ + assert len(self) == len(v) + return Vector([x1 + x2 for x1, x2 in zip(self, v)]) + + def __mul__(self, v): + """ + redefine * as Vector dot product + """ + assert len(self) == len(v) + return sum([x1 * x2 for x1, x2 in zip(self, v)]) + +l1 = [1, 2, 3] +l2 = [4, 5, 6] +v1 = Vector(l1) +v2 = Vector(l2) + +if __name__ == '__main__': + print('l1') + print(l1) + print('l1 + l2') + print(l1 + l2) + # print(l1 * l2) # TypeError + print('zip(l1, l2)') + print(zip(l1, l2)) + print('v1') + print(v1) + print('v1 + v2') + print(v1 + v2) + print('v1 * v2') + print(v1 * v2) diff --git a/_downloads/yield_example.py b/_downloads/yield_example.py new file mode 100644 index 00000000..81c9590d --- /dev/null +++ b/_downloads/yield_example.py @@ -0,0 +1,22 @@ +def counter(): + print('counter: starting counter') + i = -3 + while i < 3: + i = i + 1 + print('counter: yield', i) + yield i + return None + + +# if __name__ == '__main__': +# print "the generator function:" +# print repr(counter) +# print "call generator function" + +# c = counter() +# print "the generator:" +# print repr(c) + +# print 'iterate' +# for item in c: +# print 'received:', item diff --git a/_images/PackagingTimeline.png b/_images/PackagingTimeline.png new file mode 100644 index 00000000..933e5aef Binary files /dev/null and b/_images/PackagingTimeline.png differ diff --git a/slides_sources/source/_static/color_git_prompt.png b/_images/color_git_prompt.png similarity index 100% rename from slides_sources/source/_static/color_git_prompt.png rename to _images/color_git_prompt.png diff --git a/slides_sources/source/_static/flake8_output.png b/_images/flake8_output.png similarity index 100% rename from slides_sources/source/_static/flake8_output.png rename to _images/flake8_output.png diff --git a/_images/git_checkout_branch.png b/_images/git_checkout_branch.png new file mode 100644 index 00000000..dab12bdc Binary files /dev/null and b/_images/git_checkout_branch.png differ diff --git a/_images/git_checkout_master.png b/_images/git_checkout_master.png new file mode 100644 index 00000000..dc245a7f Binary files /dev/null and b/_images/git_checkout_master.png differ diff --git a/_images/git_commit_on_branch.png b/_images/git_commit_on_branch.png new file mode 100644 index 00000000..23143d7f Binary files /dev/null and b/_images/git_commit_on_branch.png differ diff --git a/_images/git_head.png b/_images/git_head.png new file mode 100644 index 00000000..c48c40e6 Binary files /dev/null and b/_images/git_head.png differ diff --git a/_images/git_master_branch.png b/_images/git_master_branch.png new file mode 100644 index 00000000..9c4aeb8a Binary files /dev/null and b/_images/git_master_branch.png differ diff --git a/_images/git_merge_commit.png b/_images/git_merge_commit.png new file mode 100644 index 00000000..2df3d2d3 Binary files /dev/null and b/_images/git_merge_commit.png differ diff --git a/_images/git_new_branch.png b/_images/git_new_branch.png new file mode 100644 index 00000000..a0a4ef4c Binary files /dev/null and b/_images/git_new_branch.png differ diff --git a/_images/git_new_commit.png b/_images/git_new_commit.png new file mode 100644 index 00000000..012eb847 Binary files /dev/null and b/_images/git_new_commit.png differ diff --git a/_images/git_new_commit_on_master.png b/_images/git_new_commit_on_master.png new file mode 100644 index 00000000..6c25e51a Binary files /dev/null and b/_images/git_new_commit_on_master.png differ diff --git a/_images/git_simple_timeline.png b/_images/git_simple_timeline.png new file mode 100644 index 00000000..465f546c Binary files /dev/null and b/_images/git_simple_timeline.png differ diff --git a/slides_sources/source/_static/pc_menu.png b/_images/pc_menu.png similarity index 100% rename from slides_sources/source/_static/pc_menu.png rename to _images/pc_menu.png diff --git a/_images/phd101212s.gif b/_images/phd101212s.gif new file mode 100644 index 00000000..721323e9 Binary files /dev/null and b/_images/phd101212s.gif differ diff --git a/slides_sources/source/_static/plugin_list.png b/_images/plugin_list.png similarity index 100% rename from slides_sources/source/_static/plugin_list.png rename to _images/plugin_list.png diff --git a/slides_sources/source/_static/python.png b/_images/python.png similarity index 100% rename from slides_sources/source/_static/python.png rename to _images/python.png diff --git a/_images/remotes_clone.png b/_images/remotes_clone.png new file mode 100644 index 00000000..8003dce2 Binary files /dev/null and b/_images/remotes_clone.png differ diff --git a/_images/remotes_fork.png b/_images/remotes_fork.png new file mode 100644 index 00000000..e4946961 Binary files /dev/null and b/_images/remotes_fork.png differ diff --git a/_images/remotes_start.png b/_images/remotes_start.png new file mode 100644 index 00000000..aa4839d0 Binary files /dev/null and b/_images/remotes_start.png differ diff --git a/_images/remotes_upstream.png b/_images/remotes_upstream.png new file mode 100644 index 00000000..de036593 Binary files /dev/null and b/_images/remotes_upstream.png differ diff --git a/slides_sources/source/_static/simple_prompt.png b/_images/simple_prompt.png similarity index 100% rename from slides_sources/source/_static/simple_prompt.png rename to _images/simple_prompt.png diff --git a/slides_sources/source/_static/tab_completion.png b/_images/tab_completion.png similarity index 100% rename from slides_sources/source/_static/tab_completion.png rename to _images/tab_completion.png diff --git a/slides_sources/source/_static/transmogrifier.jpg b/_images/transmogrifier.jpg similarity index 100% rename from slides_sources/source/_static/transmogrifier.jpg rename to _images/transmogrifier.jpg diff --git a/slides_sources/source/_static/two_line_prompt.png b/_images/two_line_prompt.png similarity index 100% rename from slides_sources/source/_static/two_line_prompt.png rename to _images/two_line_prompt.png diff --git a/slides_sources/source/_static/virtualenv_prompt.png b/_images/virtualenv_prompt.png similarity index 100% rename from slides_sources/source/_static/virtualenv_prompt.png rename to _images/virtualenv_prompt.png diff --git a/_sources/exercises/args_kwargs_lab.txt b/_sources/exercises/args_kwargs_lab.txt new file mode 100644 index 00000000..2adffc00 --- /dev/null +++ b/_sources/exercises/args_kwargs_lab.txt @@ -0,0 +1,71 @@ +.. _exercise_args_kwargs_lab: + +******************* +args and kwargs Lab +******************* + +Learning about ``args`` and ``kwargs`` +====================================== + +Goal: +----- + +Develop an understanding of using advanced argument passing and parameter definitons. + +If this is all confusing -- you may want to review this: + +http://stupidpythonideas.blogspot.com/2013/08/arguments-and-parameters.html + +Procedure +--------- + +**Keyword arguments:** + +* Write a function that has four optional parameters (with defaults): + + - `fore_color` + - `back_color` + - `link_color` + - `visited_color` + +* Have it print the colors (use strings for the colors) + +* Call it with a couple different parameters set + + - using just positional arguments: + + - ``func('red', 'blue', 'yellow', 'chartreuse')`` + + - using just keyword arguments: + + - ``func(link_color='red', back_color='blue')`` + + - using a combination of positional and keyword + + - ````func('purple', link_color='red', back_color='blue')`` + + - using ``*some_tuple`` and/or ``**some_dict`` + + - ``regular = ('red', 'blue')`` + + - ``links = {'link_color': 'chartreuse'}`` + + - ``func(*regular, *links)`` + +.. nextslide:: + +**Generic parameters:** + +* Write a the same function with the parameters as: + +``*args`` and ``**kwags`` + +* Have it print the colors (use strings for the colors) + +* Call it with the same various combinations of arguments used above. + +* Also have it print `args` and `kwargs` directly, so you can be sure you understand what's going on. + +* Note that in general, you can't know what will get passed into ``**kwargs`` So maybe adapt your function to be able to do something reasonable with any keywords. + + diff --git a/_sources/exercises/circle_class.txt b/_sources/exercises/circle_class.txt new file mode 100644 index 00000000..51a3f8ee --- /dev/null +++ b/_sources/exercises/circle_class.txt @@ -0,0 +1,240 @@ +.. _exercise_circle_class: + +====================== +Circle Class Excercise +====================== + +Circle Class +============ + +Goal: +------ + +The goal is to create a class that represents a simple circle. + +A Circle can be defined by either specifying the radius or the diameter, +and the user can query the circle for either its radius or diameter. + +Other abilities of a Circle instance: + + * Compute the circle's area + * Print the circle and get something nice + * Be able to add two circles together + * Be able to compare two circles to see which is bigger + * Be able to compare to see if there are equal + * (follows from above) be able to put them in a list and sort them + +.. nextslide:: + +You will use: + + - properties + - a classmethod + - a define a bunch of "special methods" + + +General Instructions: +--------------------- + +1. For each step, write a couple of unit tests that test the new features. + +2. Run these tests (and they will fail the first time) + +3. Add the code required for your tests to pass. + + +Step 1: +------- + +create class called ``Circle`` -- it's signature should look like:: + + c = Circle(the_radius) + +The radius is a required parameter (can't have a circle without one!) + +the resulting circle should have a attribute for the radius:: + + c.radius + +So you can do: + +.. code-block:: python + + >> c = Circle(4) + >> print c.radius + 4 + +Remember: tests first! + +Step 2: +------- + +Add a "diameter" property, so the user can get the diameter of the circle: + +.. code-block:: python + + >> c = Circle(4) + >> print c.diameter + 8 + +Step 3: +------- + +Set up the diameter property so that the user can set the diameter of the circle: + +.. code-block:: python + + >> c = Circle(4) + >> c.diameter = 2 + >> print c.diameter + 2 + >> print c.radius + 1 + +**NOTE** that the radius has changed! + +Step 4: +-------- + +Add an ``area`` property so the user can get the area of the circle: + +.. code-block:: python + + >> c = Circle(2) + >> print c.area + 12.566370 + +(``pi`` can be found in the math module) + +The user should not be able to set the area: + +.. code-block:: python + + >> c = Circle(2) + >> c.area = 42 + AttributeError + +Step 5: +------- + +Add an "alternate constructor" that lets the user create a Circle directly +with the diameter: + +.. code-block:: python + + >> c = Circle.from_diameter(8) + >> print c.diameter + 8 + >> print c.radius + 4 + +Step 6: +------- + +Add __str__ and __repr__ methods to your Circle class. + +Now you can print it: + +.. code-block:: ipython + + In [2]: c = Circle(4) + + In [3]: print c + Circle with radius: 4.000000 + + In [4]: repr(c) + Out[4]: 'Circle(4)' + + In [5]: d = eval(repr(c)) + + In [6]: d + Out[6]: Circle(4) + +Step 7: +-------- + +Add some of the numeric protocol to your Circle: + +You should be able to add two circles: + +.. code-block:: ipython + + In [7]: c1 = Circle(2) + + In [8]: c2 = Circle(4) + + In [9]: c1 + c2 + Out[9]: Circle(6) + +and multiply one times a number: + +.. code-block:: ipython + + In [16]: c2 * 3 + Out[16]: Circle(12) + +(what happens with ``3 * c2`` ? -- can you fix that?) + +.. nextslide:: + +Step 8: +-------- +add the ability to compare two circles: + +.. code-block:: ipython + + In [10]: c1 > c2 + Out[10]: False + + In [11]: c1 < c2 + Out[11]: True + + In [12]: c1 == c2 + Out[12]: False + + In [13]: c3 = Circle(4) + + In [14]: c2 == c3 + Out[14]: True + +.. nextslide:: + +Once the comparing is done, you should be able to sort a list of circles: + +.. code-block:: ipython + + In [18]: print circles + [Circle(6), Circle(7), Circle(8), Circle(4), Circle(0), Circle(2), Circle(3), Circle(5), Circle(9), Circle(1)] + + In [19]: circl + circle circle.py circle.pyc circles + + In [19]: circles.sort() + + In [20]: print circles + [Circle(0), Circle(1), Circle(2), Circle(3), Circle(4), Circle(5), Circle(6), Circle(7), Circle(8), Circle(9)] + +**NOTE:** make sure to write unit tests for all of this! Ideally before writing the code. + +Step 8: Optional Features: +-------------------------- + +* See if you can make "reflected" numerics do the right thing: + +.. code-block:: python + + a_circle * 3 == 3 * a_circle + +* What else makes sense: division? others? + +* Add the "augmented assignment" operators, where they make sense: + +.. code-block:: python + + a_circle += another_circle + + a_circle *= 2 + +* look through all the "magic methods" and see what makes sense for circles + + diff --git a/_sources/exercises/comprehensions_lab.txt b/_sources/exercises/comprehensions_lab.txt new file mode 100644 index 00000000..fb9152e5 --- /dev/null +++ b/_sources/exercises/comprehensions_lab.txt @@ -0,0 +1,250 @@ +.. _exercise_comprehensions: + +****************** +Comprehensions Lab +****************** + +Playing with Comprehensions +============================ + + +.. rst-class:: large left + + Goal: + +.. rst-class:: medium left + + Getting Familiar with list, set and dict comprehensions + + +List comprehensions +-------------------- + +Note: this is a bit of a "backwards" exercise -- +we show you code, you figure out what it does. + +As a result, not much to submit -- don't worry about it -- you'll have +a chance to use these in other exercises. + +.. code-block:: python + + >>> feast = ['lambs', 'sloths', 'orangutans', + 'breakfast cereals', 'fruit bats'] + + >>> comprehension = [delicacy.capitalize() for delicacy in feast] + +What is the output of: + +.. code-block:: python + + >>> comprehension[0] + ??? + + >>> comprehension[2] + ??? + +(figure it out before you try it) + +Filtering lists with list comprehensions +---------------------------------------- + +.. code-block:: python + + >>> feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals', + 'fruit bats'] + + >>> comp = [delicacy for delicacy in feast if len(delicacy) > 6] + +What is the output of: + +.. code-block:: python + + >>> len(feast) + ??? + + >>> len(comp) + ??? + +(figure it out first!) + + +Unpacking tuples in list comprehensions +--------------------------------------- + +.. code-block:: python + + >>> list_of_tuples = [(1, 'lumberjack'), (2, 'inquisition'), (4, 'spam')] + + >>> comprehension = [ skit * number for number, skit in list_of_tuples ] + +What is the output of: + +.. code-block:: python + + >>> comprehension[0] + ??? + + >>> len(comprehension[2]) + ??? + +Double list comprehensions +--------------------------- +.. code-block:: python + + >>> eggs = ['poached egg', 'fried egg'] + + >>> meats = ['lite spam', 'ham spam', 'fried spam'] + + >>> comprehension = \ + [ '{0} and {1}'.format(egg, meat) for egg in eggs for meat in meats] + +What is the output of: + +.. code-block:: python + + >>> len(comprehension) + ??? + + >>> comprehension[0] + ??? + +Set comprehensions +------------------ + +.. code-block:: python + + >>> comprehension = { x for x in 'aabbbcccc'} + +What is the output of: + +.. code-block:: python + + >>> comprehension + ??? + +Dictionary comprehensions +------------------------- + +.. code-block:: python + + >>> dict_of_weapons = {'first': 'fear', + 'second': 'surprise', + 'third':'ruthless efficiency', + 'forth':'fanatical devotion', + 'fifth': None} + >>> dict_comprehension = \ + { k.upper(): weapon for k, weapon in dict_of_weapons.items() if weapon} + +What is the output of: + +.. code-block:: python + + >>> 'first' in dict_comprehension + ??? + >>> 'FIRST' in dict_comprehension + ??? + >>> len(dict_of_weapons) + ??? + >>> len(dict_comprehension) + ??? + +Other resources +--------------- + + +See also: + +https://github.com/gregmalcolm/python_koans + +Specifically (for comprehensions): + +https://github.com/gregmalcolm/python_koans/blob/master/python3/koans/about_comprehension.py + + +Count Even Numbers +------------------ + +This is from CodingBat "count_evens" (http://codingbat.com/prob/p189616) + +*Using a list comprehension*, return the number of even integers in the given array. + +Note: the % "mod" operator computes the remainder, e.g. ``5 % 2`` is 1. + +.. code-block:: python + + count_evens([2, 1, 2, 3, 4]) == 3 + + count_evens([2, 2, 0]) == 3 + + count_evens([1, 3, 5]) == 0 + + +.. code-block:: python + + def count_evens(nums): + one_line_comprehension_here + + +``dict`` and ``set`` comprehensions +------------------------------------ + +Revisiting the dict/set lab -- see how much you can do with +comprehensions instead. + +(:ref:`exercise_dict_lab`) + +Specifically, look at these: + +First a slightly bigger, more interesting (or at least bigger..) dict: + +.. code-block:: python + + food_prefs = {"name": "Chris", + "city": "Seattle", + "cake": "chocolate", + "fruit": "mango", + "salad": "greek", + "pasta": "lasagna"} + +.. nextslide:: Working with this dict: + +1. Print the dict by passing it to a string format method, so that you +get something like: + + "Chris is from Seattle, and he likes chocolate cake, mango fruit, + greek salad, and lasagna pasta" + +2. Using a list comprehension, build a dictionary of numbers from zero +to fifteen and the hexadecimal equivalent (string is fine). +(the ``hex()`` function gives you the hexidecimal representation of a number.) + +3. Do the previous entirely with a dict comprehension -- should be a one-liner + +4. Using the dictionary from item 1: Make a dictionary using the same +keys but with the number of 'a's in each value. You can do this either +by editing the dict in place, or making a new one. If you edit in place, +make a copy first! + +.. nextslide:: + +5. Create sets s2, s3 and s4 that contain numbers from zero through twenty, +divisible 2, 3 and 4. + + a. Do this with one set comprehension for each set. + + b. What if you had a lot more than 3? -- Don't Repeat Yourself (DRY). + + - create a sequence that holds all the divisors you might want -- + could be 2,3,4, or could be any other arbitrary divisors. + + - loop through that sequence to build the sets up -- so no repeated code. + you will end up with a list of sets -- one set for each divisor in your + sequence. + + - The idea here is that when you see three (Or more!) lines of code that + are almost identical, then you you want to find a way to generalize + that code and have it act on a set of inputs, so the actual code is + only written once. + + c. Extra credit: do it all as a one-liner by nesting a set comprehension + inside a list comprehension. (OK, that may be getting carried away!) diff --git a/_sources/exercises/dict_lab.txt b/_sources/exercises/dict_lab.txt new file mode 100644 index 00000000..fe4ce49c --- /dev/null +++ b/_sources/exercises/dict_lab.txt @@ -0,0 +1,89 @@ +.. _exercise_dict_lab: + +********************** +Dictionary and Set Lab +********************** + +Learning about dictionaries and sets +==================================== + +Goal: +----- + +Learn the basic ins and outs of Python dictionaries and sets. + +Procedure +--------- + +In your student dir in the IntroPython2015 repo, create a ``session04`` dir and put in a new ``dict_lab.py`` file. + +The file should be an executable python script. That is to say that one +should be able to run the script directly like so: + +.. code-block:: bash + + $ ./dict_lab.py + +(At least on OS-X and Linux) + +-- you do that with this command: + +.. code-block:: bash + + $ chmod +x dict_lab.py + +(The +x means make this executable) + +.. nextslide:: + +Add the file to your clone of the repository and commit changes frequently +while working on the following tasks. When you are done, push your changes to +GitHub and issue a pull request. + +(if you are struggling with git -- just write the code for now) + +When the script is run, it should accomplish the following four series of +actions: + +.. nextslide:: Dictionaries 1 + +* Create a dictionary containing "name", "city", and "cake" for "Chris" from "Seattle" who likes "Chocolate". + +* Display the dictionary. + +* Delete the entry for "cake". + +* Display the dictionary. + +* Add an entry for "fruit" with "Mango" and display the dictionary. + + - Display the dictionary keys. + - Display the dictionary values. + - Display whether or not "cake" is a key in the dictionary (i.e. False) (now). + - Display whether or not "Mango" is a value in the dictionary (i.e. True). + + +.. nextslide:: Dictionaries 2 + + +* Using the dictionary from item 1: Make a dictionary using the same keys but + with the number of 't's in each value as the value. (upper and lower case?). + +.. nextslide:: Sets + +* Create sets s2, s3 and s4 that contain numbers from zero through twenty, + divisible 2, 3 and 4. + +* Display the sets. + +* Display if s3 is a subset of s2 (False) + +* and if s4 is a subset of s2 (True). + +.. nextslide:: Sets 2 + +* Create a set with the letters in 'Python' and add 'i' to the set. + +* Create a frozenset with the letters in 'marathon' + +* display the union and intersection of the two sets. diff --git a/_sources/exercises/exceptions_lab.txt b/_sources/exercises/exceptions_lab.txt new file mode 100644 index 00000000..5ff5b16b --- /dev/null +++ b/_sources/exercises/exceptions_lab.txt @@ -0,0 +1,25 @@ +.. _exercise_exceptions_lab: + +************** +Exceptions Lab +************** + +Learning Exceptions +=================== + +Just a little bit for the basics. + +Exceptions Lab +--------------- + +Improving ``input`` + +* The ``input()`` function can generate two exceptions: ``EOFError`` + or ``KeyboardInterrupt`` on end-of-file(EOF) or canceled input. + +* Create a wrapper function, perhaps ``safe_input()`` that returns ``None`` + rather rather than raising these exceptions, when the user enters ``^C`` for Keyboard Interrupt, or ``^D`` (``^Z`` on Windows) for End Of File. + +* Update your mailroom program to use exceptions (and IBAFP) to handle + malformed numeric input + diff --git a/_sources/exercises/fib_and_lucas.txt b/_sources/exercises/fib_and_lucas.txt new file mode 100644 index 00000000..86343f60 --- /dev/null +++ b/_sources/exercises/fib_and_lucas.txt @@ -0,0 +1,101 @@ +.. _exercise_fibonacci: + +************************* +Fibonacci Series Exercise +************************* + +Computing the Fibonacci and Lucas Series +======================================== + +Goal: +----- + +The `Fibonacci Series`_ is a numeric series starting with the integers 0 and 1. + +In this series, the next integer is determined by summing the previous two. + +This gives us:: + + 0, 1, 1, 2, 3, 5, 8, 13, ... + +We will write a function that computes this series -- then generalize it. + +.. _Fibonacci Series: http://en.wikipedia.org/wiki/Fibbonaci_Series + +Step 1 +------ + +* Create a new module ``series.py`` in the ``session02`` folder in your student folder. + + - In it, add a function called ``fibonacci``. + + - The function should have one parameter ``n``. + + - The function should return the ``nth`` value in the fibonacci series. + +* Ensure that your function has a well-formed ``docstring`` + +Note that the fibinacci series is naturally recusive -- the value is +defined by previous values: + +fib(n) = fib(n-2) + fib(n-1) + + +Lucas Numbers +-------------- + +The `Lucas Numbers`_ are a related series of integers that start with the +values 2 and 1 rather than 0 and 1. The resulting series looks like this:: + + 2, 1, 3, 4, 7, 11, 18, 29, ... + +.. _Lucas Numbers: http://en.wikipedia.org/wiki/Lucas_number + + +In your ``series.py`` module, add a new function ``lucas`` that returns the +``nth`` value in the *lucas numbers* series. + +Ensure that your function has a well-formed ``docstring`` + +Generalizing +------------ + +Both the *fibonacci series* and the *lucas numbers* are based on an identical +formula. + +Add a third function called ``sum_series`` with one required parameter and two +optional parameters. The required parameter will determine which element in the +series to print. The two optional parameters will have default values of 0 and +1 and will determine the first two values for the series to be produced. + +Calling this function with no optional parameters will produce numbers from the +*fibonacci series*. Calling it with the optional arguments 2 and 1 will +produce values from the *lucas numbers*. Other values for the optional +parameters will produce other series. + +**Note:** While you *could* check the input arguments, and then call one +of the functions you wrote, the idea of this exercise is to make a general +function, rather than one specialized. So you should re-impliment the code +in this function. + +In fact, you could go back and re-impliment your fibonacci and lucas +functions to call this one with particular arguments. + +Ensure that your function has a well-formed ``docstring`` + +Tests... +-------- + +Add a block of code to the end of your ``series.py`` +module. Use the block to write a series of ``assert`` statements that +demonstrate that your three functions work properly. + +Use comments in this block to inform the observer what your tests do. + +Add your new module to your git clone and commit frequently while working on +your implementation. Include good commit messages that explain concisely both +*what* you are doing and *why*. + +When you are finished, push your changes to your fork of the class repository +in GitHub and make a pull request. + diff --git a/_sources/exercises/file_lab.txt b/_sources/exercises/file_lab.txt new file mode 100644 index 00000000..44b3f656 --- /dev/null +++ b/_sources/exercises/file_lab.txt @@ -0,0 +1,55 @@ +.. _exercise_file_lab: + +******** +File LAB +******** + +A bit of practice with files +============================ + +Goal: +----- + +Get a little bit of practice with handling files and parsing simple text. + + +Paths and File Processing +-------------------------- + +* write a program which prints the full path to all files in the current + directory, one per line + +* write a program which copies a file from a source, to a destination + (without using shutil, or the OS copy command) + + - advanced: make it work for any size file: i.e. don't read the entire + contents of the file into memory at once. + + - This should work for any kind of file, so you need to open + the files in binary mode: ``open(filename, 'rb')`` (or ``'wb'`` for + writing). Note that for binary files, you can't use ``readline()`` -- + lines don't have any meaning for binary files. + + - Test it with both text and binrary files (maybe jpeg or??) + + +File reading and parsing +------------------------ + + +In the class repo, in: + +``Examples/Session01/students.txt`` + +You will find the list I generated in the first class of all the students in the class, and what programming languages they have used in the past. + +Write a little script that reads that file, and generates a list of all +the languages that have been used. + +Extra credit: keep track of how many students specified each language. + +If you've got git set up right, ``git pull upstream master`` should update +your repo. Otherwise, you can get it from gitHub: + +https://github.com/UWPCE-PythonCert/IntroPython2016/blob/master/Examples/Session01/students.txt + diff --git a/_sources/exercises/fizz_buzz.txt b/_sources/exercises/fizz_buzz.txt new file mode 100644 index 00000000..d6f19fe1 --- /dev/null +++ b/_sources/exercises/fizz_buzz.txt @@ -0,0 +1,69 @@ +.. _exercise_fizz_buzz: + +****************** +Fizz Buzz Exercise +****************** + +The Classic Fizz Buzz Problem +============================== + +.. rst-class:: left + + Fizz Buzz is a classic simple problem in computer science. + + Often used as an exercise in interviews for programmers. + + Apparently a LOT of people applying for jobs as profesional developers can't do this in an interview: + + (http://c2.com/cgi/wiki?FizzBuzzTest) + + Now that I've psyched you out -- it's really pretty straightforward. + +Goal: +----- + +* Write a program that prints the numbers from 1 to 100 inclusive. + +* But for multiples of three print "Fizz" instead of the number + +* For the multiples of five print "Buzz". + +* For numbers which are multiples of both three and five print "FizzBuzz" instead. + +Hint: +----- + +* Look up the ``%`` operator. What do these do? + + * ``10 % 7`` + * ``14 % 7`` + +(try that in iPython) + +* **Do** try to write a solution *before* looking it up -- there are a million nifty solutions posted on the web, but you'll learn a lot more if you figure it out on your own first. + +Results: +-------- + +Running your code should result in something like:: + + 1 + 2 + Fizz + 4 + Buzz + Fizz + 7 + 8 + Fizz + Buzz + 11 + Fizz + 13 + 14 + FizzBuzz + 16 + .... + + + diff --git a/_sources/exercises/grid_printer.txt b/_sources/exercises/grid_printer.txt new file mode 100644 index 00000000..41e43f57 --- /dev/null +++ b/_sources/exercises/grid_printer.txt @@ -0,0 +1,222 @@ +.. _exercise_grid_printer: + +********************* +Grid Printer Exercise +********************* + +Printing a Grid +================ + +(adapted from Downey, "Think Python", ex. 3.5) + +Goal: +----- + +Write a function that draws a grid like the following:: + + + - - - - + - - - - + + | | | + | | | + | | | + | | | + + - - - - + - - - - + + | | | + | | | + | | | + | | | + + - - - - + - - - - + + +hints +----- + +.. rst-class:: center medium + + A couple features to get you started... + +printing +-------- + +To print more than one value on a line, you can pass multiple names into the print function: + +.. code-block:: python + + print('+', '-') + +If you don't want a newline after something is printed, you tell python what you want the print to end with like so: + +.. code-block:: python + + print('+', end=' ') + print('-') + +The output of these statements is ``'+ -'``. + +(that end parameter defaults to a newline...) + +.. nextslide:: no arguments... + +A print function with no arguments ends the current line and goes to the next line: + +.. code-block:: python + + print() + + +Simple string manipulation: +--------------------------- + +You can put two strings together with the plus operator: + +.. code-block:: ipython + + In [20]: "this" + "that" + Out[20]: 'thisthat + +Particularly useful if they have been assigned names: + +.. code-block:: ipython + + In [21]: plus = '+' + + In [22]: minus = '-' + + In [23]: plus+minus+plus + Out[23]: '+-+' + +Note that you can string any number of operations together in an expression. + +.. nextslide:: multiplication of strings + +You can also multiply strings: + +.. code-block:: ipython + + In [24]: '+' * 10 + Out[24]: '++++++++++' + +And combine that with plus in a complex expression: + +.. code-block:: ipython + + In [29]: first_name = 'Chris' + + In [30]: last_name = 'Barker' + + In [31]: 5 * '*' + first_name +' ' + last_name + 5 * '*' + Out[31]: '*****Chris Barker*****' + +Note that there are better ways to build up complex strings -- we'll get to that later. + +Now you've got what you need to print that grid... + +Part 2 +======= + +.. rst-class:: center medium + + Making it more general + +Make it a function +------------------ + +One of the points of writing functions is so you can write code that does similar things, but customized to input parameters. So what if we want to be able to print that grid at an arbitrary size? + +Write a function ``print_grid(n)`` that takes one integer argument +and prints a grid just like before, BUT the size of the +grid is given by the argument. + +For example, ``print_grid(11)`` prints the grid in the above picture. + +``print_grid(3)`` would print a smaller grid:: + + + - + - + + | | | + + - + - + + | | | + + - + - + + +.. nextslide:: + +``print_grid(15)`` prints a larger grid:: + + + - - - - - - - + - - - - - - - + + | | | + | | | + | | | + | | | + | | | + | | | + | | | + + - - - - - - - + - - - - - - - + + | | | + | | | + | | | + | | | + | | | + | | | + | | | + + - - - - - - - + - - - - - - - + + +.. nextslide:: + +This problem is underspecified. Do something reasonable. + +Part 3: +======= + +Even more general... + +A function with two parameters +------------------------------- + +Write a function that draws a similar grid with a specified number of rows and columns, and each cell a given size. + +for example, ``print_grid2(3,4)`` results in:: + + + - - - - + - - - - + - - - - + + | | | | + | | | | + | | | | + | | | | + + - - - - + - - - - + - - - - + + | | | | + | | | | + | | | | + | | | | + + - - - - + - - - - + - - - - + + | | | | + | | | | + | | | | + | | | | + + - - - - + - - - - + - - - - + + +.. nextslide:: + +What to do about rounding? -- you decide. + +Another example: ``print_grid2(5,3)``:: + + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + | | | | | | + | | | | | | + | | | | | | + + - - - + - - - + - - - + - - - + - - - + + + + diff --git a/_sources/exercises/html_builder.txt b/_sources/exercises/html_builder.txt new file mode 100644 index 00000000..8f9781b2 --- /dev/null +++ b/_sources/exercises/html_builder.txt @@ -0,0 +1,308 @@ +.. _exercise_html_renderer: + +======================= +HTML Renderer Excercise +======================= + +HTML Renderer +============= + +Goal: +------ + +The goal is to create a set of classes to render html pages -- in a "pretty printed" way. i.e nicely indented and human readable. We'll try to get to all the features required to render: + +:download:`sample_html.html <./sample_html.html>` + +The exercise is broken down into a number of steps -- each requiring a few more OO concepts in Python. + +General Instructions: +--------------------- + +For each step, add the required functionality. There is example code to run your code for each step in: ``code\session06\run_html_render.py`` + +name your file: ``html_render.py`` -- so it can be imported by ``run_html_render.py`` + +You should be able to run that code at each step, uncommenting each new step in ``run_html_render.py`` as you go. + +It builds up a html tree, and then calls the ``render()`` method of your element to render the page. + +It uses a ``cStringIO`` object (like a file, but in memory) to render to memory, then dumps it to the console, and writes a file. Take a look at the code at the end to make sure you understand it. + +The html generated at each step is in the files: ``test_html_ouput?.html`` + +At each step, your results should look similar that those (maybe not identical...) + + +Step 1: +------- + +Create an ``Element`` class for rendering an html element (xml element). + +It should have class attributes for the tag name ("html" first) and the indentation (spaces to indent for pretty printing) + +The constructor signature should look like + +.. code-block:: python + + Element(content=None) + +where ``content`` is a string + +It should have an ``append`` method that can add another string to the content. + +It should have a ``render(file_out, ind = "")`` method that renders the tag and the strings in the content. + +``file_out`` could be any file-like object ( i.e. have a ``write()`` method ). + +.. nextslide:: + +``ind`` is a string with the indentation level in it: the amount that the tag should be indented for pretty printing. + + - This is a little tricky: ``ind`` will be the amount that this element should be indented already. It will be from zero (an empty string) to a lot of spaces, depending on how deep it is in the tree. + +The amount of indentation should be set by the class attribute: ``indent`` + +NOTE: don't worry too much about indentation at this stage -- the primary goal is to get proper, compliant html. i.e. the opening and closing tags rendered correctly. Worry about cleaning up the indentation once you've got that working. + +You should now be able to render an html tag with text in it as contents. + +See: step 1. in ``run_html_render.py`` + +Step 2: +-------- + +Create a couple subclasses of ``Element``, for a ``html``, ````, and ``

`` tag. All you should have to do is override the ``tag`` class attribute (you may need to add a ``tag`` class attribute to the Element class first...). + +Now you can render a few different types of element. + +Extend the ``Element.render()`` method so that it can render other elements inside the tag in addition to strings. Simple recursion should do it. i.e. it can call the ``render()`` method of the elements it contains. You'll need to be smart about setting the ``ind`` optional parameter -- so that the nested elements get indented correctly. + +Figure out a way to deal with the fact that the contained elements could be either simple strings or ``Element`` s with render methods (there are a few ways to handle that...). + +You should now be able to render a basic web page with an html tag around +the whole thing, a ```` tag inside, and multiple ``

`` tags inside that, with text inside that. And all indented nicely. + +See ``test_html_output2.html`` + +NOTE: when you run step 2 in ``run_html_render.py``, you will want o comment out step 1 -- that way you'll only get one set of output. + +Step 3: +-------- + +Create a ```` element -- simple subclass. + +Create a ``OneLineTag`` subclass of ``Element``: + +* It should override the render method, to render everything on one line -- for the simple tags, like:: + + PythonClass - Session 6 example + +Create a ``Title`` subclass of ``OneLineTag`` class for the title. + +You should now be able to render an html doc with a head element, with a +title element in that, and a body element with some ``

`` elements and some text. + +See ``test_html_output3.html`` + +Step 4: +-------- + +Extend the ``Element`` class to accept a set of attributes as keywords to the +constructor, ie. (``run_html_render.py``) + +.. code-block:: python + + Element("some text content", id="TheList", style="line-height:200%") + +( remember ``**kwargs``? ) + +The render method will need to be extended to render the attributes properly. + +You can now render some ``

`` tags (and others) with attributes + +See ``test_html_output4.html`` + +Step 5: +-------- + +Create a ``SelfClosingTag`` subclass of Element, to render tags like:: + +


and
(horizontal rule and line break). + +You will need to override the render method to render just the one tag and +attributes, if any. + +Create a couple subclasses of ``SelfClosingTag`` for and
and
+ +See ``test_html_output5.html`` + +Step 6: +------- + +Create a ``A`` class for an anchor (link) element. Its constructor should look like:: + + A(self, link, content) + +where link is the link, and content is what you see. It can be called like so:: + + A(u"http://google.com", u"link to google") + +You should be able to subclass from ``Element``, and only override the ``__init__`` --- Calling the ``Element`` ``__init__`` from the ``A __init__`` + +You can now add a link to your web page. + +See ``test_html_output6.html`` + +Step 7: +-------- + +Create ``Ul`` class for an unordered list (really simple subclass of ``Element``) + +Create ``Li`` class for an element in a list (also really simple) + +Add a list to your web page. + +Create a ``Header`` class -- this one should take an integer argument for the +header level. i.e

,

,

, called like + +.. code-block:: python + + H(2, "The text of the header") + +for an

header + +It can subclass from ``OneLineTag`` -- overriding the ``__init__``, then calling the superclass ``__init__`` + +See ``test_html_output7.html`` + +Step 8: +-------- + +Update the ``Html`` element class to render the "" tag at the head of the page, before the html element. + +You can do this by subclassing ``Element``, overriding ``render()``, but then calling the ``Element`` render from the new render. + +Create a subclass of ``SelfClosingTag`` for ```` (like for ``
`` and ``
`` and add the meta element to the beginning of the head element to give your document an encoding. + +The doctype and encoding are HTML 5 and you can check this at: http://validator.w3.org. + +You now have a pretty full-featured html renderer -- play with it, add some +new tags, etc.... + +See ``test_html_output8.html`` + + +HTML Primer +============ + +.. rst-class:: medium + + The very least you need to know about html to do this assigment. + +If you are familar with html, then this will all make sense to you. If you have +never seen html before, this might be a bit intimidating, but you really don't +need to know much to do this assignment. + +First of all, sample output from each step is provided. So all you really need +to do is look at that, and make your code do the same thing. But it does help to +know a little bit about what you are doing. + +HTML +---- + +HTML is "Hyper Text Markup Language". Hypertext, because it can contain links +to other pages, and markup language means that text is "marked up" with +instructions about how to format the text, etc. + +Here is a good basic intro: + +http://www.w3schools.com/html/html_basic.asp + +And there are countless others online. + +But here is a tiny intro of just what you need to know for this project. + +Elements +-------- + +Modern HTML is a particular dialect of XML (eXrensible Markup Language), +which is itself a special case of SGML (Standard Generalized Markup Language) + +It inherits from SGML a basic structure: each piece of the document is an element. each element is described by a "tag". each tag has a different meaning, but they all have the same structure:: + + some content + +that is, the tag name is surrounded by < and >, which marks the beginning of +the element, and the end of the element is indicated by the same tag with a slash. + +The real power is that these elements can be nested arbitrarily deep. In order to keep that all readable, we often want to indent the content inside the tags, so it's clear what belongs with what. That is one of the tricky bits of this assignment. + +Basic tags +---------- + +.. code-block:: html + + is the core tag indicating the entire document + +

is a single paragraph of text

+ + is the tag that indicated the text of the document + + defines the header of the document -- a place for metadata + +Attributes: +------------ + +In addition to the tag name and the content, extra attributes can be attached to a tag. These are added to the "opening tag", with name="something", another_name="somethign else" format: + +.. code-block:: html + +

+ +There can be all sorts of stuff stored in attributes -- some required for specific tags, some extra, like font sizes and colors. Note that since tags can essentially have any attributes, your code will need to support that -- doesn't it kind of look like a dict? And keyword arguments? + +Special Elements +---------------- + +The general structure is everything is between and opening and closing tag. But some elements don't really have content -- just attributes. So the slash goes at the end of the tag, after the attributes. We can call these self-closing tags: + +.. code-block:: html + + + +To make a link, you use an "anchor" tag: ````. It required attributes to indicate what the link is: + +.. code-block:: html + + link + +the ``href`` attribute is the link (hyper reference). + +To make a bulleted list, you use a

    tag (unordered list), and inside that, you put individual list elements
  • : + +.. code-block:: html + +
      +
    • + The first item in a list +
    • +
    • + This is the second item +
    • +
    + +Note that the list itself, and the list items can both take various attributes (all tags can...) + +Section Headers are created with "h" tags:

    is the biggest (highest level), and there is

    ,

    , etc. for sections, sub sections, subsub sections. + +.. code-block:: html + +

    PythonClass - Class 6 example

    + +I think that's all you need to know! + + + + + diff --git a/_sources/exercises/html_renderer.txt b/_sources/exercises/html_renderer.txt new file mode 100644 index 00000000..d38dc6e0 --- /dev/null +++ b/_sources/exercises/html_renderer.txt @@ -0,0 +1,566 @@ +.. _exercise_html_renderer: + +====================== +HTML Renderer Exercise +====================== + +HTML Renderer +============= + +Ever need to generate some HTML? + +And not want to write all those tags yourself? + +Goal: +------ + +The goal is to create a set of classes to render html pages -- in a "pretty printed" way. + +i.e. nicely indented and human readable. + +We'll try to get to all the features required to render: + +:download:`sample_html.html <./sample_html.html>` + +Take a look at it with "view source" in your browser -- or open in a text editor -- it's also in the Examples dir. + +If you don't know html -- just look at the example and copy that.... + +The exercise is broken down into a number of steps -- each requiring a few more OO concepts in Python. + +General Instructions: +--------------------- + +For each step, add the required functionality. There is example code to run your code for each step in: ``Examples\session07\run_html_render.py`` + +Name your file: ``html_render.py`` -- so it can be imported by ``run_html_render.py`` + +You should be able to run that code at each step, uncommenting each new step in ``run_html_render.py`` as you go. + +It builds up an html tree, and then calls the ``render()`` method of your element to render the page. + +It uses a ``StringIO`` object (like a file, but in memory) to render to memory, then dumps it to the console, and writes a file. Take a look at the code at the end to make sure you understand it. + +The html generated at each step will be in the files: ``test_html_ouput?.html`` + +At each step, your results should look similar that those (maybe not identical...) + +Unit tests +------------ + +Use "test driven development": + +In addition to checking if the output is what you expect with the running script -- you should also write unit tests as you go. + +Each new line of code should have a test that will run it -- *before* you write that code. + +That is: + + 1. write a test that exercises the next step in your process + 2. run the tests -- the new test will fail + 3. write your code... + 4. run the tests. If it still fails, go back to step 3... + + +Step 1: +------- + +Create an ``Element`` class for rendering an html element (xml element). + +It should have class attributes for the tag name ("html" first) and the indentation (spaces to indent for pretty printing) + +The initializer signature should look like + +.. code-block:: python + + Element(content=None) + +where ``content`` is expected to be a string + +It should have an ``append`` method that can add another string to the content. + +So your class will need a way to store the content in a way that you can keep adding more to it. + +.. nextslide:: + +It should have a ``render(file_out, ind = "")`` method that renders the tag and the strings in the content. + +``file_out`` could be any file-like object ( i.e. have a ``write()`` method ). + +``ind`` is a string with the indentation level in it: the amount that the tag should be indented for pretty printing. + + - This is a little tricky: ``ind`` will be the amount that this element should be indented already. It will be from zero (an empty string) to a lot of spaces, depending on how deep it is in the tree. + +The amount of each level of indentation should be set by the class attribute: ``indent`` + +NOTE: don't worry too much about indentation at this stage -- the primary goal is to get proper, compliant html. i.e. the opening and closing tags rendered correctly. Worry about cleaning up the indentation once you've got that working. See "Note on indentation" below for more explaination. + +.. nextslide:: + +So this ``render()`` method takes a file-like object, and calls its ``write()`` method, writing the html for a tag. Something like:: + + + Some content. Some more content. + <\html> + +You should now be able to render an html tag with text in it as contents. + +See: step 1. in ``run_html_render.py`` + +Step 2: +-------- + +Create a couple subclasses of ``Element``, for each of ````, ````, and ``

    `` tags. All you should have to do is override the ``tag`` class attribute (you may need to add a ``tag`` class attribute to the ``Element`` class first, if you haven't already). + +Now you can render a few different types of element. + +Extend the ``Element.render()`` method so that it can render other elements inside the tag in addition to strings. Simple recursion should do it. i.e. it can call the ``render()`` method of the elements it contains. You'll need to be smart about setting the ``ind`` optional parameter -- so that the nested elements get indented correctly. (again, this is a secondary concern...) + +Figure out a way to deal with the fact that the contained elements could be either simple strings or ``Element`` s with render methods (there are a few ways to handle that...). Think about "Duck Typing" and EAFP. See the section 'Notes on handling "duck typing"' and the end of the Exercise for more. + +.. nextslide:: + +You should now be able to render a basic web page with an ```` tag around the whole thing, a ```` tag inside, and multiple ``

    `` tags inside that, with text inside that. And all indented nicely. + +See ``test_html_output2.html`` + +NOTE: when you run step 2 in ``run_html_render.py``, you will want to comment out step 1 -- that way you'll only get one set of output. + +Step 3: +-------- + +Create a ```` element -- a simple subclass. + +Create a ``OneLineTag`` subclass of ``Element``: + +* It should override the render method, to render everything on one line -- for the simple tags, like:: + + PythonClass - Session 6 example + +Create a ``Title`` subclass of ``OneLineTag`` class for the title. + +You should now be able to render an html doc with a head element, with a +title element in that, and a body element with some ``

    `` elements and some text. + +See ``test_html_output3.html`` + +Step 4: +-------- + +Extend the ``Element`` class to accept a set of attributes as keywords to the +constructor, e.g. ``run_html_render.py`` + +.. code-block:: python + + Element("some text content", id="TheList", style="line-height:200%") + +html elements can take essentially any attributes -- so you can't hard-code these particular ones. ( remember ``**kwargs``? ) + +The render method will need to be extended to render the attributes properly. + +You can now render some ``

    `` tags (and others) with attributes + +See ``test_html_output4.html`` + +.. nextslide:: the "class" attribute. + +NOTE: if you do "proper" CSS+html, then you wouldn't specify style directly in element attributes. + +Rather you would set the "class" attribute:: + +

    + This is my recipe for making curry purely with chocolate +

    + +However, if you try this as a keywork argument in Python: + +.. code-block:: ipython + + In [1]: P("some content", class="intro") + File "", line 1 + P("some content", class="intro") + ^ + SyntaxError: invalid syntax + +Huh? + +"class" is a reserved work in Python -- for making classes. +So it can't be used as a keywork argument. + +But it's a fine key in a dict, so you can put it in a dict, and pass it in with ``**``: + +.. code-block:: python + + attrs = {'class': 'intro'} + P("some content", **attrs) + +You could also special-case this in your code -- so your users could use "clas" +with one s, and you could tranlate it in the generated html. + + +Step 5: +-------- + +Create a ``SelfClosingTag`` subclass of Element, to render tags like:: + +
    and
    (horizontal rule and line break). + +You will need to override the render method to render just the one tag and +attributes, if any. + +Create a couple subclasses of ``SelfClosingTag`` for and
    and
    + +Note that you now have a couple render methods -- is there repeated code in them? + +Can you refactor the common parts into a separate method that all the render methods can call? And do all your tests still pass (you do have tests for everything, don't you?) after refactoring? + +See ``test_html_output5.html`` + +Step 6: +------- + +Create an ``A`` class for an anchor (link) element. Its constructor should look like:: + + A(self, link, content) + +where ``link`` is the link, and ``content`` is what you see. It can be called like so:: + + A("http://google.com", "link to google") + +You should be able to subclass from ``Element``, and only override the ``__init__`` --- calling the ``Element`` ``__init__`` from the ``A __init__`` + +You can now add a link to your web page. + +See ``test_html_output6.html`` + +Step 7: +-------- + +Create ``Ul`` class for an unordered list (really simple subclass of ``Element``) + +Create ``Li`` class for an element in a list (also really simple) + +Add a list to your web page. + +Create a ``Header`` class -- this one should take an integer argument for the +header level. i.e

    ,

    ,

    , called like + +.. code-block:: python + + H(2, "The text of the header") + +for an

    header + +It can subclass from ``OneLineTag`` -- overriding the ``__init__``, then calling the superclass ``__init__`` + +See ``test_html_output7.html`` + +Step 8: +-------- + +Update the ``Html`` element class to render the "" tag at the head of the page, before the html element. + +You can do this by subclassing ``Element``, overriding ``render()``, but then calling the ``Element`` render from the new render. + +Create a subclass of ``SelfClosingTag`` for ```` (like for ``
    `` and ``
    `` and add the meta element to the beginning of the head element to give your document an encoding. + +The doctype and encoding are HTML 5 and you can check this at: http://validator.w3.org. + +You now have a pretty full-featured html renderer -- play with it, add some +new tags, etc.... + +See ``test_html_output8.html`` + +Note on indentation +=================== + +Indentation is not stricly required for html -- html ignores most whitespace. + +But it can make it much easier to read for humans, and it's a nice excercise to see how one might make it nice. + +There is also more than one way to indent html -- so you have a bit of flexibility here. + +So: + +* You probably ``ind`` to be an optional argument to render -- so it will not indent if nothing is passed in. And that lets you write the code without indentation first if you like. + +* But ultimately, you want your code to USE the ind parameter -- it is supposed to indicate how much this entire tag is already indented. + +* When this one gets rendered, you don't know where it is in a potentially deeply nested hierarchy -- it could be at the top level or ten levels deep. passing ``ind`` into the render method is how this is communicated. + +* You have (at least) two options for how to indicate level of indentation: + + - It could be a integer indicating number of levels of indentation + - It could, more simply, be a bunch of spaces. + +* You want to have the amount of spaces per indentation defined as a class attribute of the base class (the ``Element`` class). That way, you could change it in one place, and it would change everywhere an remain consistent. + + + +Notes on handling "duck typing" +=============================== + +.. rst-class:: left + + In this exercise, we need to deal with the fact that XML (and thus HTML) allows *either* plain text *or* other tags to be the content of a tag. Our code also needs to handle the fact that there are two possible types that we need to be able to render. + + There are two primary ways to address this (and multiple ways to actually write the code for each of these). + + 1) Make sure that the content only has renderable objects in it. + + 2) Make sure the render() method can handle either type on the fly + + The difference is where you handle the multiple types -- in the render method itself, or ahead of time. + +The ahead of time option: +------------------------- + +You can handle it ahead of time by creating a simple object that wraps a string and gives it a render method. As simple as: + +.. code-block:: python + + class TextWrapper: + """ + A simple wrapper that creates a class with a render method + for simple text + """ + def __init__(self, text): + self.text = text + + def render(self, file_out, current_ind=""): + file_out.write(current_ind) + file_out.write(self.text) + +.. nextslide:: + +You could require your users to use the wrapper, so instead of just appending a string, they would do: + +.. code-block:: python + + an_element.append(TextWRapper("the string they want to add")) + +But this is not very Pythonic style -- it's OO heavy. Strings for text are so common you want to be able to simply use them: + +.. code-block:: python + + an_element.append("the string they want to add") + +So much easier. + +To accomplish this, you can update the ``append()`` method to put this wrapper around plain strings when something new is added. + + +Checking if it's the right type +------------------------------- + +How do you decide if the wrapper is required? + +**Checking it it's an instance of Element:** + +You could check and see if the object being appended is an Element: + +.. code-block:: python + + if isinstance(content, Element): + self.content.append(content) + else: + self.content.append(TextWrapper(content)) + +This would work well, but closes the door to using any other type that may not be a strict subclsss of Element, but can render itself. Not too bad in this case, but in general, frowned upon in Python. + +.. nextslide:: + +Alternatively, you could check for the string type: + +.. code-block:: python + + if isinstance(content, str): + self.content.append(TextWrapper(content)) + else: + self.content.append(content) + +I think this is a little better -- strings are a pretty core type in python, it's not likely that anyone is going to need to use a "string-like" object. + +Duck Typing +----------- + +The Python model of duck typing is: If quacks like a duck, then treat it like a duck. + +But in this case, we're not actually rendering the object at this stage, so calling the method isn't appropriate. + +**Checking for an attribute** + +Instead of calling the method, see if it's there. You can do that with ``hasattr()`` + +check if the passed-in object has a ``render()`` attribute: + +.. code-block:: python + + if hasattr(content, 'render'): + self.content.append(content) + else: + self.content.append(TextWrapper(str(content)) + + +Note that I added a ``str()`` call too -- so you can pass in anything -- it will get stringified -- this will be ugly for many objects, but will work fine for numbers and other simple objects. + +This is my favorite. ``html_render_wrap.py`` in Solutions demonstrates some core bits of this approach. + + +Duck Typing on the Fly +---------------------- + +The other option is to simply put both elements and text in the content list, and figure out what to do in the ``render()`` method. + +Again, you could type check -- but I prefer the duck typing approach, and EAFP: + +.. code-block:: python + + try: + content.render(out_file) + except AttributeError: + outfile.write(content) + +If content is a simple string then it won't have a render method, and an ``AttributeError`` will be raised. + +You can catch that, and simply write the content directly instead. + +.. nextslide:: + +You may want to turn it into a string, first:: + + outfile.write(str(content)) + +Then you could write just about anything -- numbers, etc. + + +Where did the Exception come from? +---------------------------------- + +**Caution** + +If the object doesn't have a ``render`` method, then an AttributeError will be raised. But what if it does have a render method, but that method is broken? + +Depending on what's broken, it could raise any number of exceptions. Most will not get caught by the except clause, and will halt the program. + +But if, just by bad luck, it has an bug that raises an ``AttributeError`` -- then this could catch it, and try to simply write it out instead. So you may get something like: ```` in the middle of your html. + +**The beauty of testing** + +If you have a unit test that calls every render method in your code -- then it should catch that error, and in the unit test it will be clear where it is coming from. + + +HTML Primer +============ + +.. rst-class:: medium + + The very least you need to know about html to do this assignment. + +.. rst-class:: left + + If you are familiar with html, then this will all make sense to you. If you have never seen html before, this might be a bit intimidating, but you really don't need to know much to do this assignment. + + First of all, sample output from each step is provided. So all you really need to do is look at that, and make your code do the same thing. But it does help understand a little bit about what you trying to do. + +HTML +---- + +HTML is "Hyper Text Markup Language". Hypertext, because it can contain links +to other pages, and markup language means that text is "marked up" with +instructions about how to format the text, etc. + +Here is a good basic intro: + +http://www.w3schools.com/html/html_basic.asp + +And there are countless others online. + +As html is XML -- the XML intro is a good source of the XML syntax, too: + +http://www.w3schools.com/xml/default.asp + +But here is a tiny intro of just what you need to know for this project. + +Elements +-------- + +Modern HTML is a particular dialect of XML (eXtensible Markup Language), +which is itself a special case of SGML (Standard Generalized Markup Language) + +It inherits from SGML a basic structure: each piece of the document is an element. Each element is described by a "tag". Each tag has a different meaning, but they all have the same structure:: + + some content + +That is, the tag name is surrounded by < and >, which marks the beginning of +the element, and the end of the element is indicated by the same tag with a slash. + +The real power is that these elements can be nested arbitrarily deep. In order to keep that all readable, we often want to indent the content inside the tags, so it's clear what belongs with what. That is one of the tricky bits of this assignment. + + +Basic tags +---------- + +.. code-block:: html + + is the core tag indicating the entire document + +

    is a single paragraph of text

    + + is the tag that indicated the text of the document + + defines the header of the document -- a place for metadata + +Attributes: +------------ + +In addition to the tag name and the content, extra attributes can be attached to a tag. These are added to the "opening tag", with name="something", another_name="somethign else" format: + +.. code-block:: html + +

    + +There can be all sorts of stuff stored in attributes -- some required for specific tags, some extra, like font sizes and colors. Note that since tags can essentially have any attributes, your code will need to support that -- doesn't it kind of look like a dict? And keyword arguments? + +Special Elements +---------------- + +The general structure is everything in between the opening and closing tag. But some elements don't really have content -- just attributes. So the slash goes at the end of the tag, after the attributes. We can call these self-closing tags: + +.. code-block:: html + + + +To make a link, you use an "anchor" tag: ````. It requires attributes to indicate what the link is: + +.. code-block:: html + + link + +The ``href`` attribute is the link (hyper reference). + +lists +----- + +To make a bulleted list, you use a

      tag (unordered list), and inside that, you put individual list items
    • : + +.. code-block:: html + +
        +
      • + The first item in a list +
      • +
      • + This is the second item +
      • +
      + +Note that the list itself *and* the list items can both take various attributes (all tags can...) + +Section Headers are created with "h" tags:

      is the biggest (highest level), and there is

      ,

      , etc. for sections, sub sections, subsub sections... + +.. code-block:: html + +

      PythonClass - Class 7 example

      + +I think that's all you need to know! diff --git a/_sources/exercises/index.txt b/_sources/exercises/index.txt new file mode 100644 index 00000000..78ac470e --- /dev/null +++ b/_sources/exercises/index.txt @@ -0,0 +1,77 @@ +========= +Exercises +========= + +Contents: +========= + +.. rst-class:: left + + +Session 2: +---------- +.. toctree:: + :maxdepth: 1 + + grid_printer + fizz_buzz + fib_and_lucas + +Session 3: +---------- +.. toctree:: + :maxdepth: 1 + + slicing + list_lab + string_formatting + rot13 + mailroom + +Session 4: +---------- +.. toctree:: + :maxdepth: 1 + + dict_lab + file_lab + kata_fourteen + +Session 5: +---------- +.. toctree:: + :maxdepth: 1 + + exceptions_lab + comprehensions_lab + +Session 6: +---------- +.. toctree:: + :maxdepth: 1 + + args_kwargs_lab + + +Session 7: +---------- +.. toctree:: + :maxdepth: 1 + + html_renderer + +Session 8: +----------- +.. toctree:: + :maxdepth: 1 + + circle_class + sparse_array + +Session 9: +---------- +.. toctree:: + :maxdepth: 1 + + lambda_magic + trapezoid \ No newline at end of file diff --git a/_sources/exercises/kata_fourteen.txt b/_sources/exercises/kata_fourteen.txt new file mode 100644 index 00000000..b7552bcf --- /dev/null +++ b/_sources/exercises/kata_fourteen.txt @@ -0,0 +1,141 @@ +.. _exercise_trigrams: + +========================================= +Kata Fourteen: Tom Swift Under Milk Wood +========================================= + +Adapted from Dave Thomas's work: + +http://codekata.com/kata/kata14-tom-swift-under-the-milkwood/ + + + +Trigrams +========= + +Trigrams can be used to mutate text into new, surreal, forms. But what +heuristics do we apply to get a reasonable result? + +The Problem +------------ + +As a boy, one of my treats was go to the shops on a Saturday and spend part +of my allowance on books; for a nine-year old, I had quite a collection of +Tom Swift and Hardy Boys. Wouldn’t it be great to be able to create +more and more of these classic books, to be able to generate a new Tom +Swift adventure on demand? + + +OK, perhaps not. But that won’t stop us trying. I coded up a quick +program to generate some swash-buckling scientific adventure on demand. It +came up with: + + ... it was in the wind that was what he thought was his companion. I + think would be a good one and accordingly the ship their situation + improved. Slowly so slowly that it beat the band! You’d think no one + was a low voice. "Don’t take any of the elements and the + inventors of the little Frenchman in the enclosed car or cabin completely + fitted up in front of the gas in the house and wringing her hands. + "I’m sure they’ll fall!" + + She looked up at them. He dug a mass of black vapor which it had + refused to accept any. As for Mr. Swift as if it goes too high I’ll + warn you and you can and swallow frequently. That will make the airship was + shooting upward again and just before the raid wouldn’t have been + instrumental in capturing the scoundrels right out of jail." + +.. nextslide:: + +Stylistically, it’s Victor Appleton meets Dylan Thomas. Technically, +it’s all done with trigrams. + +Trigram analysis is very simple. Look at each set of three adjacent words +in a document. Use the first two words of the set as a key, and remember +the fact that the third word followed that key. Once you’ve finished, +you know the list of individual words that can follow each two word +sequence in the document. For example, given the input:: + + I wish I may I wish I might + +You might generate:: + + "I wish" => ["I", "I"] + "wish I" => ["may", "might"] + "may I" => ["wish"] + "I may" => ["I"] + +.. nextslide:: + +This says that the words "I wish" are twice followed by the word +"I", the words "wish I" are followed once by +"may" and once by "might" and so on. + +To generate new text from this analysis, choose an arbitrary word pair as a +starting point. Use these to look up a random next word (using the table +above) and append this new word to the text so far. This now gives you a +new word pair at the end of the text, so look up a potential next word +based on these. Add this to the list, and so on. In the previous example, +we could start with "I may". The only possible next word is +"I", so now we have:: + + I may I + +The last two words are "may I", so the next word is +"wish". We then look up "I wish", and find our choice +is constrained to another "I".:: + + I may I wish I + +.. nextslide:: + +Now we look up "wish I", and find we have a choice. Let’s +choose "may":: + + I may I wish I may + +Now we’re back where we started from, with "I may." +Following the same sequence, but choosing "might" this time, we +get:: + + I may I wish I may I wish I might + +At this point we stop, as no sequence starts "I might." + + +.. nextslide:: + +Given a short input text, the algorithm isn’t too interesting. Feed +it a book, however, and you give it more options, so the resulting output +can be surprising. + +For this kata, try implementing a trigram algorithm that generates a couple +of hundred words of text using a book-sized file as input. +`Project Gutenberg `_ is a good source of online +books (Tom Swift and His Airship is `here `_.) + +Be warned that these files have DOS line endings (carriage return followed by +newline). + +.. nextslide:: + + +There is a copy of sherlock holmes right here: + +:download:`sherlock.txt <./sherlock.txt>`. + +And a shorter copy for testing: + +:download:`sherlock_small.txt <./sherlock_small.txt>`. + + +Objectives +----------- + +Kata’s are about trying something many times. In this one, what +we’re experimenting with is not just the code, but the heuristics of +processing the text. What do we do with punctuation? Paragraphs? Do we have +to implement backtracking if we chose a next word that turns out to be a +dead end? + +I’ll fire the signal and the fun will commence... + diff --git a/_sources/exercises/lambda_magic.txt b/_sources/exercises/lambda_magic.txt new file mode 100644 index 00000000..edcde112 --- /dev/null +++ b/_sources/exercises/lambda_magic.txt @@ -0,0 +1,61 @@ +.. _exercise_lambda_magic: + +************************ +lambda and keyword Magic +************************ + +Goals +===== + +.. rst-class:: left + + * A bit of lambda + * functions as objects + * keyword evaluation + + +Task +---- + +Write a function that returns a list of n functions, +such that each one, when called, will return the input value, +incremented by an increasing number. + +Use a for loop, ``lambda``, and a keyword argument + +**Extra credit:** + +Do it with a list comprehension, instead of a for loop + +Not clear? here's what you should get... + +Example calling code +--------------------- + +.. code-block:: ipython + + In [96]: the_list = function_builder(4) + ### so the_list should contain n functions (callables) + In [97]: the_list[0](2) + Out[97]: 2 + ## the zeroth element of the list is a function that add 0 + ## to the input, hence called with 2, returns 2 + In [98]: the_list[1](2) + Out[98]: 3 + ## the 1st element of the list is a function that adds 1 + ## to the input value, thus called with 2, returns 3 + In [100]: for f in the_list: + print(f(5)) + .....: + 5 + 6 + 7 + 8 + ### If you loop through them all, and call them, each one adds one more + to the input, 5... i.e. the nth function in the list adds n to the input. + +.. nextslide:: + +See the test code in Examples/Session09 + + diff --git a/_sources/exercises/list_lab.txt b/_sources/exercises/list_lab.txt new file mode 100644 index 00000000..36943bfb --- /dev/null +++ b/_sources/exercises/list_lab.txt @@ -0,0 +1,113 @@ +.. _exercise_list_lab: + +******** +List Lab +******** + +Learning about lists +==================== + +After: + +http://www.upriss.org.uk/python/session5.html + +Goal: +----- + +Learn the basic ins and outs of Python lists. + +hint +---- + +to query the user for info at the command line, you use: + +.. code-block:: python + + response = input("a prompt for the user > ") + +``response`` will be a string of whatever the user types (until a ). + + +Procedure +--------- + +In your student dir in the IntroPython2015 repo, create a ``session03`` dir and put in a new ``list_lab.py`` file. + +The file should be an executable python script. That is to say that one +should be able to run the script directly like so: + +.. code-block:: bash + + $ ./list_lab.py + +(At least on OS-X and Linux) + +-- you do that with this command: + +.. code-block:: bash + + $ chmod +x list_lab.py + +(The +x means make this executable) + +The file will also need this on the first line:: + + #!/usr/bin/env python3 + +This is known as the "she-bang" line -- it tells the shell how to execute that file -- in this case, with ``python3`` + +NOTE: on Windows, there is a python launcher which, if everything is configured correctly look at that line to know you want python3 if there is more than one python on your system. + +.. nextslide:: + +Add the file to your clone of the repository and commit changes frequently +while working on the following tasks. When you are done, push your changes to +GitHub and issue a pull request. + +(if you are struggling with git -- just write the code for now) + +When the script is run, it should accomplish the following four series of +actions: + +.. nextslide:: Series 1 + +- Create a list that contains "Apples", "Pears", "Oranges" and "Peaches". +- Display the list. +- Ask the user for another fruit and add it to the end of the list. +- Display the list. +- Ask the user for a number and display the number back to the user and the + fruit corresponding to that number (on a 1-is-first basis). +- Add another fruit to the beginning of the list using "+" and display the + list. +- Add another fruit to the beginning of the list using insert() and display the list. +- Display all the fruits that begin with "P", using a for loop. + + +.. nextslide:: Series 2 + +Using the list created in series 1 above: + +- Display the list. +- Remove the last fruit from the list. +- Display the list. +- Ask the user for a fruit to delete and find it and delete it. +- (Bonus: Multiply the list times two. Keep asking until a match is found. Once found, delete all occurrences.) + +.. nextslide:: Series 3 + +Again, using the list from series 1: + +- Ask the user for input displaying a line like "Do you like apples?" +- for each fruit in the list (making the fruit all lowercase). +- For each "no", delete that fruit from the list. +- For any answer that is not "yes" or "no", prompt the user to answer with one + of those two values (a while loop is good here): +- Display the list. + +.. nextslide:: Series 4 + +Once more, using the list from series 1: + +- Make a copy of the list and reverse the letters in each fruit in the copy. +- Delete the last item of the original list. Display the original list and the + copy. diff --git a/_sources/exercises/mailroom.txt b/_sources/exercises/mailroom.txt new file mode 100644 index 00000000..93425ad1 --- /dev/null +++ b/_sources/exercises/mailroom.txt @@ -0,0 +1,158 @@ +.. _exercise_mailroom: + +******** +Mailroom +******** + +A complete program +================== + +Using basic data types and logic for a full program + +Goal: +----- + +You work in the mail room at a local charity. Part of your job is to write +incredibly boring, repetitive emails thanking your donors for their generous +gifts. You are tired of doing this over an over again, so you've decided to +let Python help you out of a jam. + +The program +----------- + +Write a small command-line script called ``mailroom.py``. This script should be executable. The script should accomplish the following goals: + +* It should have a data structure that holds a list of your donors and a + history of the amounts they have donated. This structure should be populated + at first with at least five donors, with between 1 and 3 donations each + +* The script should prompt the user (you) to choose from a menu of 3 actions: + 'Send a Thank You' or 'Create a Report' or 'quit') + +Sending a Thank You +------------------- + +* If the user (you) selects 'Send a Thank You', prompt for a Full Name. + + * If the user types 'list', show them a list of the donor names and re-prompt + * If the user types a name not in the list, add that name to the data structure and use it. + * If the user types a name in the list, use it. + * Once a name has been selected, prompt for a donation amount. + * Turn the amount into a number -- it is OK at this point for the program to crash if someone types a bogus amount. + * Once an amount has been given, add that amount to the donation history of + the selected user. + * Finally, use string formatting to compose an email thanking the donor for + their generous donation. Print the email to the terminal and return to the + original prompt. + +**It is fine to forget new donors once the script quits running.** + +Creating a Report +------------------ + +* If the user (you) selected 'Create a Report' print a list of your donors, + sorted by total historical donation amount. + + - Include Donor Name, total donated, number of donations and average donation amount as values in each row. You do not need to print out all their donations, just the summary info. + - Using string formatting, format the output rows as nicely as possible. The end result should be tabular (values in each column should align with those above and below) + - After printing this report, return to the original prompt. + +* At any point, the user should be able to quit their current task and return + to the original prompt. + +* From the original prompt, the user should be able to quit the script cleanly + + +Your report should look somethign like this:: + + Donor Name | Total Given | Num Gifts | Average Gift + ------------------------------------------------------------------ + William Gates, III $ 653784.49 2 $ 326892.24 + Mark Zuckerberg $ 16396.10 3 $ 5465.37 + Jeff Bezos $ 877.33 1 $ 877.33 + Paul Allen $ 708.42 3 $ 236.14 + +Guidelines +---------- + +First, factor your script into separate functions. Each of the above +tasks can be accomplished by a series of steps. Write discreet functions +that accomplish individual steps and call them. + +Second, use loops to control the logical flow of your program. Interactive +programs are a classic use-case for the ``while`` loop. + +Of course, ``input()`` will be useful here. + +Put the functions you write into the script at the top. + +Put your main interaction into an ``if __name__ == '__main__'`` block. + +Finally, use only functions and the basic Python data types you've learned +about so far. There is no need to go any farther than that for this assignment. + +Submission +---------- + +As always, put the new file in your student directory in a ``session03`` +directory, and add it to your clone early. Make frequent commits with +good, clear messages about what you are doing and why. + +When you are done, push your changes and make a pull request. + +.. _exercise_mailroom_plus: + +Adding dicts... +--------------- + + +For the next week (after Session04) + +You should have been able to do all that with the basic data types: + +numbers, strings, lists and tuples. + +But once you've learned about dictionaries (Session04) you may be able to re-write it a bit more simply and efficiently. + + * Update mailroom from last week to: + + - Use dicts where appropriate + - Write a full set of letters to everyone to individual files on disk + - See if you can use a dict to switch between the users selections + - Try to use a dict and the .format() method to do the letter as one + big template -- rather than building up a big string in parts. + +Example: + +.. code-block:: ipython + + In [3]: d + Out[3]: {'first_name': 'Chris', 'last_name': 'Barker'} + + + In [5]: "My name is {first_name} {last_name}".format(**d) + Out[5]: 'My name is Chris Barker' + +Don't worry too much about the "**" -- we'll get into the details later, but for now, it means, more or less -- pass this whole dict in as a bunch of keyword arguments. + + +.. _exercise_mailroom_exeptions: + +Adding Exceptions +----------------- + +**After Session05:** + +* Exceptions: + +Now that you've learned about Exception handling, you can update your code to handle errors better -- like when a user inputs bad data. + +* Comprehensions: + +Can you use comprehensions to clean up your code a bit? + +* Tests + +Add some tests.. + + diff --git a/_sources/exercises/rot13.txt b/_sources/exercises/rot13.txt new file mode 100644 index 00000000..0763adf4 --- /dev/null +++ b/_sources/exercises/rot13.txt @@ -0,0 +1,48 @@ +.. _exercise_rot13: + +***** +ROT13 +***** + +Goal +---- + +Get used to working with the number values for characters + +Get a bit of practice with string methods and string processing + + +ROT13 encryption +----------------- + +The ROT13 encryption scheme is a simple substitution cypher where each letter +in a text is replace by the letter 13 away from it (imagine the alphabet as a +circle, so it wraps around). + +The task +-------- + +Add a python module named ``rot13.py`` to the session03 dir in your student dir. This module should provide at least one function called ``rot13`` that takes any amount of text and returns that same text encrypted by ROT13. + +This function should preserve whitespace, punctuation and capitalization. + +Your module should include an ``if __name__ == '__main__':`` block with tests (asserts) that demonstrate that your ``rot13`` function and any helper functions you add work properly. + + +.. nextslide:: A bit more + +There is a "short-cut" available that will help you accomplish this task. Some +spelunking in `the documentation for strings`_ should help you to find it. If +you do find it, using it is completely fair game. + +As usual, add your new file to your local clone right away. Make commits +early and often and include commit messages that are descriptive and concise. + +When you are done, if you want me to review it, push your changes to github +and issue a pull request. + +try decrypting this: + +"Zntargvp sebz bhgfvqr arne pbeare" + +.. _the documentation for strings: https://docs.python.org/3/library/stdtypes.html#string-methods diff --git a/_sources/exercises/slicing.txt b/_sources/exercises/slicing.txt new file mode 100644 index 00000000..61747eb8 --- /dev/null +++ b/_sources/exercises/slicing.txt @@ -0,0 +1,25 @@ +.. _exercise_slicing: + +*********** +Slicing Lab +*********** + +Goal +==== + +Get the basics of sequence slicing down + +Tasks +----- + +Write some functions that: + +* return a sequence with the first and last items exchanged. +* return a sequence with every other item removed +* return a sequence with the first and last 4 items removed, and every other item in between +* return a sequence reversed (just with slicing) +* return a sequence with the middle third, then last third, then the first third in the new order + +NOTE: +these should work with ANY sequence -- but you can use strings to test, if you like. + diff --git a/_sources/exercises/sparse_array.txt b/_sources/exercises/sparse_array.txt new file mode 100644 index 00000000..f627c82a --- /dev/null +++ b/_sources/exercises/sparse_array.txt @@ -0,0 +1,86 @@ +.. _exercise_sparse_array: + +====================== +Sparse Array Exercise +====================== + +Sparse Array +============ + +.. rst-class:: medium + + Goal: + +Learn how to emulate a built-in class. + +Sparse Array: +------------- + +Oftentimes, at least in computation programming, we have large arrays of data that hold mostly zeros. + +These are referred to as "sparse" as the information in them is widely scattered, or sparse. + +Since they are mostly zeros, it can be memory and computationally efficient to store only the value that are non-zero. + +But you want it to look like a regular array in user code. + +In the real world, these are usually 2 dimensional arrays. But to keep it a bit simpler, we'll make a 1 dimensional sparse array in this class. + +(feel free to make it 2d for an extra challenge!) + +A Sparse array class +-------------------- + +A spare array class should present to the user the same interface as a regular list. + +Some ideas of how to do that: + +* Internally, it can store the values in a dict, with the index as the keys. So that only the indexes with non-zero values will be stored. + +* It should take a sequence of values as an initializer: + +.. code-block:: python + + sa = SparseArray([1,2,0,0,0,0,3,0,0,4]) + +* you should be able to tell how long it is: + +.. code-block:: python + + len(my_array) + + This will give its "virtual" length -- with the zeros + +.. nextslide:: + +* It should support getting and setting particular elements via indexing: + +.. code-block:: python + + sa[5] = 12 + sa[3] = 0 # the zero won't get stored! + val = sa[13] # it should get a zero if not set + +* It should support deleting an element by index: + +.. code-block:: python + + del sa[4] + +* It should raise an ``IndexError`` if you try to access an index beyond the end. + +* it should have an append() method + +.. nextslide:: + +* Can you make it support slicing? + +* How else can you make it like a list? + +.. code-block:: ipython + + In [10]: my_array = SparseArray( (1,0,0,0,2,0,0,0,5) ) + In [11]: my_array[4] + Out[11]: 2 + In [12]: my_array[2] + Out[12]: 0 diff --git a/_sources/exercises/string_formatting.txt b/_sources/exercises/string_formatting.txt new file mode 100644 index 00000000..f01556d9 --- /dev/null +++ b/_sources/exercises/string_formatting.txt @@ -0,0 +1,111 @@ +.. _exercise_string_formatting: + +********************* +String Formatting Lab +********************* + +Building up strings +=================== + +.. rst-class:: left + +For reference: + +The official reference docs: + +https://docs.python.org/3/library/string.html#string-formatting + +And a more human-readable intro: + +https://pyformat.info/ + +And a nice "Cookbook": + +https://mkaz.tech/python-string-format.html + + +A Couple Exercises +------------------ + +* Write a format string that will take: + + ``( 2, 123.4567, 10000)`` + + and produce: + + ``'file_002 : 123.46, 1.00e+04'`` + +**Note:** the idea behind the "file_002" is that if you have a bunch of files that you want to name with numbers that can be sorted, you need to "pad" the numbers with zeros to get the right sort order. + +.. nextslide:: + +For example: + +.. code-block:: ipython + + In [10]: fnames = ['file1', 'file2', 'file10', 'file11'] + In [11]: fnames.sort() + In [12]: fnames + Out[12]: ['file1', 'file10', 'file11', 'file2'] + +That is probably not what you want. However: + +.. code-block:: ipython + + In [1]: fnames = ['file001', 'file002', 'file010', 'file011'] + In [3]: sorted(fnames) + Out[3]: ['file001', 'file002', 'file010', 'file011'] + +That works! + +So you want to find a string formatting operator that will "pad" the number with zeros for you. + +Dynamically Building up format strings +-------------------------------------- + +* Rewrite: + +``"the 3 numbers are: {:d}, {:d}, {:d}".format(1,2,3)`` + +to take an arbitrary number of values. + +Trick: You can pass in a tuple of values to a function with a ``*``: + +.. code-block:: ipython + + In [52]: t = (1,2,3) + + In [53]: "the 3 numbers are: {:d}, {:d}, {:d}".format(*t) + Out[53]: 'the 3 numbers are: 1, 2, 3' + +.. nextslide:: + +The idea here is that you may have a tuple of three numbers, but might also have 4 or 5 or.... + +So you can dynamically build up the format string to accommodate the length of the tuple. + +The string object has the ``format()`` method, so you can call it with a string that is bound to a name, not just a string literal. For example: + +.. code-block:: ipython + + In [16]: fstring = "{:d}, {:d}" + + In [17]: nums = (34, 56) + + In [18]: fstring.format(*nums) + Out[18]: '34, 56' + +So how would you make an fstring that was the right length for an arbitrary tuple? + +.. nextslide:: + +Put your code in a function that will return the formatted string like so: + +.. code-block:: ipython + + In [20]: formatter((2,3,5)) + Out[20]: 'the 3 numbers are: 2, 3, 5' + + In [21]: formatter((2,3,5,7,9)) + Out[21]: 'the 5 numbers are: 2, 3, 5, 7, 9' + diff --git a/_sources/exercises/trapezoid.txt b/_sources/exercises/trapezoid.txt new file mode 100644 index 00000000..bf6c97ef --- /dev/null +++ b/_sources/exercises/trapezoid.txt @@ -0,0 +1,295 @@ +.. _exercise_trapezoidal_rule: + +***************** +Trapezoidal Rule +***************** + +Passing functions around +========================= + + +.. rst-class:: medium left + + Goal: + +.. rst-class:: left + + Making use of functions as objects -- functions that act on functions. + + +Trapezoidal rule +---------------- + +The "trapezoidal rule": + +https://en.wikipedia.org/wiki/Trapezoidal_rule + +Is one of the easiest "quadrature" methods. + +Otherwise known as computing a definite integral, or, simply, + +Computing the area under a curve. + +The task +-------- + +Your task is to write a ``trapz()`` function that will compute the area under an arbitrary function, using the trapezoidal rule. + +The function will take another function as an argument, as well as the start and end points to compute, and return the area under the curve. + +Example: +-------- + +.. code-block:: python + + def line(x): + '''a very simple straight horizontal line at y = 5''' + return 5 + + area = trapz(line, 0, 10) + + area + 50 + +About the simplest "curve" you can have is a horizontal straight line, in this case, at y = 5. The area under that line from 0 to 10 is a rectangle that is 10 wide and 5 high, so with an area of 50. + +Of course in this case, it's easiest to simply multiply the height times the width, but we want a function that will work for **Any** curve. + +HINT: this simple example could be a good test case! + +The Solution: +------------- + +Your function definition should look like: + +.. code-block:: python + + def trapz(fun, a, b): + """ + Compute the area under the curve defined by + y = fun(x), for x between a and b + + :param fun: the function to evaluate + :type fun: a function that takes a single parameter + + :param a: the start point for teh integration + :type a: a numeric value + + :param b: the end point for the integration + :type b: a numeric value + """ + pass + +.. nextslide:: + +In the function, you want to compute the following equation: + +.. math:: + + area = \frac{b-a}{2N}(f(x_0) + 2f(x_1) + 2f(x_2) + \dotsb + 2f(x_{N-1}) + f(x_N)) + +So you will need to: + + - create a list of x values from a to b (maybe 100 or so values to start) + + - compute the function for each of those values and double them + + - add them all up + + - multiply by the half of the difference between a and b divided by the number of steps. + +.. nextslide:: + +Note that the first and last values are not doubled, so it may be more efficient to rearrange it like this: + +.. math:: + + area = \frac{b-a}{N} \left( \frac{f(x_0) + f(x_{N})}{2} + \sum_{i=1}^{N-1} f(x_i) \right) + +Can you use comprehensions for this? + +NOTE: ``range()`` only works for integers -- how can you deal with that? + +.. nextslide:: + +Once you have that, it should work for any function that can be evaluated between a and b. + +Try it for some built-in math functions, like ``math.sin`` + +tests +----- + +Do this using test-drive development. + +A few examples of analytical solutions you can use for tests: + +A simple horizontal line -- see above. + +.. nextslide:: + +A sloped straight line: + +.. math:: + + \int_a^b y = mx + B = \frac{1}{2} m (b^2-a^2) + B (b-a) + +The quadratic: + +.. math:: + + \int_a^b y = Ax^2 + Bx + C = \frac{A}{3} (b^3-a^3) + \frac{B}{2} (b^2-a^2) + C (b-a) + + +The sine function: + +.. math:: + + \int_a^b \sin(x) = \cos(a) - \cos(b) + +Computational Accuracy +---------------------- + +In the case of the linear functions, the result should theoretically be exact. But with the vagaries of floating point math may not be. + +And for non-linear functions, the result will certainly not be exact. + +So you want to check if the answer is *close* to what you expect. + +In py3.5 -- there is an ``isclose()`` function (PEP485) + +https://www.python.org/dev/peps/pep-0485/ + +In earlier pythons -- you'll need your own. There is one in: + +``Examples/Session09/test_trapz.py`` + + + +Stage two: +---------- + +Some functions need extra parameters to do their thing. But the above will only handle a single parameter. For example, a quadratic function: + +.. math:: + + y = A x^2 + Bx + C + +Requires values for A, B, and C in order to compute y from an given x. + +You could write a specialized version of this function for each A, B, and C: + +.. code-block:: python + + def quad1(x): + return 3 * x**2 + 2*x + 4 + +But then you need to write a new function for any value of these parameters you might need. + +.. nextslide:: + +Instead, you can pass in A, B and C each time: + +.. code-block:: python + + def quadratic(x, A=0, B=0, C=0): + return A * x**2 + B * x + C + +Nice and general purpose. + +But how would we compute the area under this function? + +The function we wrote above only passes x in to the function it is integrating. + +Passing arguments through: +-------------------------- + +Update your trapz() function so that you can give it a function that takes arbitrary extra arguments, either positional or keyword, after the x. + +So you can do: + +.. code-block:: python + + trapz(quadratic, 2, 20, A=1, B=3, C=2) + +or + +.. code-block:: python + + trapz(quadratic, 2, 20, 1, 3, C=2) + +or + +.. code-block:: python + + coef = {'A':1, 'B':3, 'C': 2} + trapz(quadratic, 2, 20, **coef) + +.. nextslide:: + +**NOTE:** Make sure this will work with ANY function, with **ANY** additional positional or keyword arguments -- not just this particular function. + +This is pretty conceptually challenging -- but it's very little code! + +If you are totally lost -- look at the lecture notes from previous classes -- how can you both accept and pass arbitrary arguments to/from a function? + +.. nextslide:: + +You want your trapz function to take ANY function that can take ANY arbitrary extra arguments -- not just the quadratic function, and not just ``A,B, and C``. So good to test with another example. + +The generalized sine function is: + +.. math:: + + A \sin(\omega t) + +where :math:`A` is the amplitude, and :math:`\omega` is the frequency of the function. In this case, the area under the curve from a to b is: + +.. math:: + + \frac{A}{\omega} \left( \cos(\omega a) - \cos(\omega b) \right) + +The test code has a test for this one, too. + +Currying +-------- + +Another way to solve the above problem is to use the original ``trapz``, and create a custom version of the quadratic() function instead. + +Write a function that takes ``A, B, and C`` as arguments, and returns a function that evaluates the quadratic for those particular coefficients. + +Try passing the results of this into your ``trapz()`` and see if you get the same answer. + +partial +------- + +Do the above with ``functools.partial`` as well. + +Extra credit +------------ + +This isn't really the point of the exercise, but see if you can make it dynamically accurate. + +How accurate it is depends on how small the chunks are that you break the function up into. + +See if you can think of a way to dynamically determine how small a step you should use. + +This is one for the math and computational programming geeks! + + + + + + + + + + + + + + + + + + + diff --git a/_sources/extra_topics.txt b/_sources/extra_topics.txt new file mode 100644 index 00000000..39062e0a --- /dev/null +++ b/_sources/extra_topics.txt @@ -0,0 +1,131 @@ +.. _extra_topics: + +************ +Extra Topics +************ + +Here are some extra topics that we didn't have time for in the regular class sessions: + +============================== +Closures and function Currying +============================== + +Defining specialized functions on the fly + +Closures +-------- + +"Closures" and "Currying" are cool CS terms for what is really just defining functions on the fly. + +you can find a "proper" definition here: + +https://en.wikipedia.org/wiki/Closure_(computer_programming) + +but I even have trouble following that. + +So let's go straight to an example: + +.. nextslide:: + +.. code-block:: python + + def counter(start_at=0): + count = [start_at] + def incr(): + count[0] += 1 + return count[0] + return incr + +What's going on here? + +We have stored the ``start_at`` value in a list. + +Then defined a function, ``incr`` that adds one to the value in the list, and returns that value. + +[ Quiz: why is it: ``count = [start_at]``, rather than just ``count=start_at`` ] + +.. nextslide:: + +So what type of object do you get when you call ``counter()``? + +.. code-block:: ipython + + In [37]: c = counter(start_at=5) + + In [38]: type(c) + Out[38]: function + +So we get a function back -- makes sense. The ``def`` defines a function, and that function is what's getting returned. + +Being a function, we can, of course, call it: + +.. code-block:: ipython + + In [39]: c() + Out[39]: 6 + + In [40]: c() + Out[40]: 7 + +Each time is it called, it increments the value by one. + +.. nextslide:: + +But what happens if we call ``counter()`` multiple times? + +.. code-block:: ipython + + In [41]: c1 = counter(5) + + In [42]: c2 = counter(10) + + In [43]: c1() + Out[43]: 6 + + In [44]: c2() + Out[44]: 11 + +So each time ``counter()`` is called, a new function is created. And that function has its own copy of the ``count`` object. This is what makes in a "closure" -- it carries with it the scope in which is was created. + +the returned ``incr`` function is a "curried" function -- a function with some parameters pre-specified. + +``functools.partial`` +--------------------- + +The ``functools`` module in the standard library provides utilities for working with functions: + +https://docs.python.org/3.5/library/functools.html + +Creating a curried function turns out to be common enough that the ``functools.partial`` function provides an optimized way to do it: + +What functools.partial does is: + + * Makes a new version of a function with one or more arguments already filled in. + * The new version of a function documents itself. + +Example: + +.. code-block:: python + + def power(base, exponent): + """returns based raised to the give exponent""" + return base ** exponent + +Simple enough. but what if we wanted a specialized ``square`` and ``cube`` function? + +We can use ``functools.partial`` to *partially* evaluate the function, giving us a specialized version: + +square = partial(power, exponent=2) +cube = partial(power, exponent=3) + +Reading: +-------- + +http://www.pydanny.com/python-partials-are-fun.html + +https://pymotw.com/3/functools/ + +http://www.programiz.com/python-programming/closure + +https://www.clear.rice.edu/comp130/12spring/curry/ + diff --git a/_sources/homework/circle_class.txt b/_sources/homework/circle_class.txt new file mode 100644 index 00000000..65293e70 --- /dev/null +++ b/_sources/homework/circle_class.txt @@ -0,0 +1,242 @@ +.. _homework_circle_class: + +================================== +Circle Class Homework Assignment +================================== + +Circle Class +============ + +Goal: +------ + +The goal is to create a class that represents a simple circle. + +A Circle can be defined by either specifying the radius or the diameter, +and the user can query the circle for either its radius or diameter. + +Other abilities of a Circle instance: + + * Compute the circle's area + * Print the circle and get something nice + * Be able to add two circles together + * Be able to compare two circles to see which is bigger + * Be able to compare to see if there are equal + * (follows from above) be able to put them in a list and sort them + +.. nextslide:: + +This exercise should use "new style classes" i.e. inherit from ``object`` + +You will also use: + + - properties + - a classmethod + - a define a bunch of "special methods" + + +General Instructions: +--------------------- + +1. For each step, write a couple of unit tests that test the new features. + +2. Run these tests (and they will fail the first time) + +3. Add the code required for your tests to pass. + + +Step 1: +------- + +create class called ``Circle`` -- it's signature should look like:: + + c = Circle(the_radius) + +The radius is a required parameter (can't have a circle without one!) + +the resulting circle should have a attribute for the radius:: + + c.radius + +So you can do: + +.. code-block:: python + + >> c = Circle(4) + >> print c.radius + 4 + +Remember: tests first! + +Step 2: +------- + +Add a "diameter" property, so the user can get the diameter of the circle: + +.. code-block:: python + + >> c = Circle(4) + >> print c.diameter + 8 + +Step 3: +------- + +Set up the diameter property so that the user can set the diameter of the circle: + +.. code-block:: python + + >> c = Circle(4) + >> c.diameter = 2 + >> print c.diameter + 2 + >> print c.radius + 1 + +**NOTE** that the radius has changed! + +Step 4: +-------- + +Add an ``area`` property so the user can get the area of the circle: + +.. code-block:: python + + >> c = Circle(2) + >> print c.area + 12.566370 + +(``pi`` can be found in the math module) + +The user should not be able to set the area: + +.. code-block:: python + + >> c = Circle(2) + >> c.area = 42 + AttributeError + +Step 5: +------- + +Add an "alternate constructor" that lets the user create a Circle directly +with the diameter: + +.. code-block:: python + + >> c = Circle.from_diameter(8) + >> print c.diameter + 8 + >> print c.radius + 4 + +Step 6: +------- + +Add __str__ and __repr__ methods to your Circle class. + +Now you can print it: + +.. code-block:: ipython + + In [2]: c = Circle(4) + + In [3]: print c + Circle with radius: 4.000000 + + In [4]: repr(c) + Out[4]: 'Circle(4)' + + In [5]: d = eval(repr(c)) + + In [6]: d + Out[6]: Circle(4) + +Step 7: +-------- + +Add some of the numeric protocol to your Circle: + +You should be able to add two circles: + +.. code-block:: ipython + + In [7]: c1 = Circle(2) + + In [8]: c2 = Circle(4) + + In [9]: c1 + c2 + Out[9]: Circle(6) + +and multiply one times a number: + +.. code-block:: ipython + + In [16]: c2 * 3 + Out[16]: Circle(12) + +(what happens with ``3 * c2`` ? -- can you fix that?) + +.. nextslide:: + +Step 8: +-------- +add the ability to compare two circles: + +.. code-block:: ipython + + In [10]: c1 > c2 + Out[10]: False + + In [11]: c1 < c2 + Out[11]: True + + In [12]: c1 == c2 + Out[12]: False + + In [13]: c3 = Circle(4) + + In [14]: c2 == c3 + Out[14]: True + +.. nextslide:: + +Once the comparing is done, you should be able to sort a list of circles: + +.. code-block:: ipython + + In [18]: print circles + [Circle(6), Circle(7), Circle(8), Circle(4), Circle(0), Circle(2), Circle(3), Circle(5), Circle(9), Circle(1)] + + In [19]: circl + circle circle.py circle.pyc circles + + In [19]: circles.sort() + + In [20]: print circles + [Circle(0), Circle(1), Circle(2), Circle(3), Circle(4), Circle(5), Circle(6), Circle(7), Circle(8), Circle(9)] + +**NOTE:** make sure to write unit tests for all of this! Ideally before writing the code. + +Step 8: Optional Features: +-------------------------- + +* See if you can make "reflected" numerics do the right thing: + +.. code-block:: python + + a_circle * 3 == 3 * a_circle + +* What else makes sense: division? others? + +* Add the "augmented assignment" operators, where they make sense: + +.. code-block:: python + + a_circle += another_circle + + a_circle *= 2 + +* look through all the "magic methods" and see what makes sense for circles + + diff --git a/slides_sources/source/homework/html_builder.rst b/_sources/homework/html_builder.txt similarity index 55% rename from slides_sources/source/homework/html_builder.rst rename to _sources/homework/html_builder.txt index 2f5ffad0..d1345998 100644 --- a/slides_sources/source/homework/html_builder.rst +++ b/_sources/homework/html_builder.txt @@ -11,10 +11,10 @@ Goal: ------ The goal is to create a set of classes to render html pages -- in a "pretty printed" way. i.e nicely indented and human readable. We'll try to get to all the features required to render: - + :download:`sample_html.html <./sample_html.html>` -The exercise is broken down into a number of steps -- each requiring a few more OO concepts in Python. +The exercise is broken down into a number of steps -- each requiring a few more OO concepts in Python. General Instructions: --------------------- @@ -37,53 +37,56 @@ At each step, your results should look similar that those (maybe not identical.. Step 1: ------- -Create an ``Element`` class for rendering an html element (xml element). - +Create an ``Element`` class for rendering an html element (xml element). + It should have class attributes for the tag name ("html" first) and the indentation (spaces to indent for pretty printing) - + The constructor signature should look like -.. code-block:: python +.. code-block:: python Element(content=None) where ``content`` is a string It should have an ``append`` method that can add another string to the content. - + It should have a ``render(file_out, ind = "")`` method that renders the tag and the strings in the content. ``file_out`` could be any file-like object ( i.e. have a ``write()`` method ). .. nextslide:: - + ``ind`` is a string with the indentation level in it: the amount that the tag should be indented for pretty printing. - This is a little tricky: ``ind`` will be the amount that this element should be indented already. It will be from zero (an empty string) to a lot of spaces, depending on how deep it is in the tree. The amount of indentation should be set by the class attribute: ``indent`` - + +NOTE: don't worry too much about indentation at this stage -- the primary goal is to get proper, compliant html. i.e. the opening and closing tags rendered correctly. Worry about cleaning up the indentation once you've got that working. + You should now be able to render an html tag with text in it as contents. See: step 1. in ``run_html_render.py`` - + Step 2: -------- -Create a couple subclasses of ``Element``, for a ```` tag and ``

      `` tag. All you should have to do is override the ``tag`` class attribute (you may need to add a ``tag`` class attribute to the Element class first...). +Create a couple subclasses of ``Element``, for a ``html``, ````, and ``

      `` tag. All you should have to do is override the ``tag`` class attribute (you may need to add a ``tag`` class attribute to the Element class first...). Now you can render a few different types of element. - + Extend the ``Element.render()`` method so that it can render other elements inside the tag in addition to strings. Simple recursion should do it. i.e. it can call the ``render()`` method of the elements it contains. You'll need to be smart about setting the ``ind`` optional parameter -- so that the nested elements get indented correctly. Figure out a way to deal with the fact that the contained elements could be either simple strings or ``Element`` s with render methods (there are a few ways to handle that...). You should now be able to render a basic web page with an html tag around -the whole thing, a ```` tag inside, and multiple ``

      `` tags inside that, -with text inside that. And all indended nicely. +the whole thing, a ```` tag inside, and multiple ``

      `` tags inside that, with text inside that. And all indented nicely. See ``test_html_output2.html`` +NOTE: when you run step 2 in ``run_html_render.py``, you will want o comment out step 1 -- that way you'll only get one set of output. + Step 3: -------- @@ -92,16 +95,16 @@ Create a ```` element -- simple subclass. Create a ``OneLineTag`` subclass of ``Element``: * It should override the render method, to render everything on one line -- for the simple tags, like:: - + PythonClass - Session 6 example - + Create a ``Title`` subclass of ``OneLineTag`` class for the title. - + You should now be able to render an html doc with a head element, with a title element in that, and a body element with some ``

      `` elements and some text. See ``test_html_output3.html`` - + Step 4: -------- @@ -109,32 +112,32 @@ Extend the ``Element`` class to accept a set of attributes as keywords to the constructor, ie. (``run_html_render.py``) .. code-block:: python - + Element("some text content", id="TheList", style="line-height:200%") ( remember ``**kwargs``? ) - + The render method will need to be extended to render the attributes properly. -You can now render some ``

      `` tags (and others) with attributes +You can now render some ``

      `` tags (and others) with attributes See ``test_html_output4.html`` - + Step 5: -------- Create a ``SelfClosingTag`` subclass of Element, to render tags like:: - +


      and
      (horizontal rule and line break). - + You will need to override the render method to render just the one tag and attributes, if any. - + Create a couple subclasses of ``SelfClosingTag`` for and
      and
      See ``test_html_output5.html`` - -Step 6: + +Step 6: ------- Create a ``A`` class for an anchor (link) element. Its constructor should look like:: @@ -142,11 +145,11 @@ Create a ``A`` class for an anchor (link) element. Its constructor should look l A(self, link, content) where link is the link, and content is what you see. It can be called like so:: - + A(u"http://google.com", u"link to google") - + You should be able to subclass from ``Element``, and only override the ``__init__`` --- Calling the ``Element`` ``__init__`` from the ``A __init__`` - + You can now add a link to your web page. See ``test_html_output6.html`` @@ -155,39 +158,151 @@ Step 7: -------- Create ``Ul`` class for an unordered list (really simple subclass of ``Element``) - + Create ``Li`` class for an element in a list (also really simple) - + Add a list to your web page. - + Create a ``Header`` class -- this one should take an integer argument for the header level. i.e

      ,

      ,

      , called like .. code-block:: python - + H(2, "The text of the header") for an

      header - + It can subclass from ``OneLineTag`` -- overriding the ``__init__``, then calling the superclass ``__init__`` See ``test_html_output7.html`` - + Step 8: -------- Update the ``Html`` element class to render the "" tag at the head of the page, before the html element. - + You can do this by subclassing ``Element``, overriding ``render()``, but then calling the ``Element`` render from the new render. - + Create a subclass of ``SelfClosingTag`` for ```` (like for ``
      `` and ``
      `` and add the meta element to the beginning of the head element to give your document an encoding. - + The doctype and encoding are HTML 5 and you can check this at: http://validator.w3.org. - + You now have a pretty full-featured html renderer -- play with it, add some new tags, etc.... See ``test_html_output8.html`` - \ No newline at end of file +HTML Primer +============ + +.. rst-class:: medium + + The very least you need to know about html to do this assigment. + +If you are familar with html, then this will all make sense to you. If you have +never seen html before, this might be a bit intimidating, but you really don't +need to know much to do this assignment. + +First of all, sample output from each step is provided. So all you really need +to do is look at that, and make your code do the same thing. But it does help to +know a little bit about what you are doing. + +HTML +---- + +HTML is "Hyper Text Markup Language". Hypertext, because it can contain links +to other pages, and markup language means that text is "marked up" with +instructions about how to format the text, etc. + +Here is a good basic intro: + +http://www.w3schools.com/html/html_basic.asp + +And there are countless others online. + +But here is a tiny intro of just what you need to know for this project. + +Elements +-------- + +Modern HTML is a particular dialect of XML (eXrensible Markup Language), +which is itself a special case of SGML (Standard Generalized Markup Language) + +It inherits from SGML a basic structure: each piece of the document is an element. each element is described by a "tag". each tag has a different meaning, but they all have the same structure:: + + some content + +that is, the tag name is surrounded by < and >, which marks the beginning of +the element, and the end of the element is indicated by the same tag with a slash. + +The real power is that these elements can be nested arbitrarily deep. In order to keep that all readable, we often want to indent the content inside the tags, so it's clear what belongs with what. That is one of the tricky bits of this assignment. + +Basic tags +---------- + +.. code-block:: html + + is the core tag indicating the entire document + +

      is a single paragraph of text

      + + is the tag that indicated the text of the document + + defines the header of the document -- a place for metadata + +Attributes: +------------ + +In addition to the tag name and the content, extra attributes can be attached to a tag. These are added to the "opening tag", with name="something", another_name="somethign else" format: + +.. code-block:: html + +

      + +There can be all sorts of stuff stored in attributes -- some required for specific tags, some extra, like font sizes and colors. Note that since tags can essentially have any attributes, your code will need to support that -- doesn't it kind of look like a dict? And keyword arguments? + +Special Elements +---------------- + +The general structure is everything is between and opening and closing tag. But some elements don't really have content -- just attributes. So the slash goes at the end of the tag, after the attributes. We can call these self-closing tags: + +.. code-block:: html + + + +To make a link, you use an "anchor" tag: ````. It required attributes to indicate what the link is: + +.. code-block:: html + + link + +the ``href`` attribute is the link (hyper reference). + +To make a bulleted list, you use a

        tag (unordered list), and inside that, you put individual list elements
      • : + +.. code-block:: html + +
          +
        • + The first item in a list +
        • +
        • + This is the second item +
        • +
        + +Note that the list itself, and the list items can both take various attributes (all tags can...) + +Section Headers are created with "h" tags:

        is the biggest (highest level), and there is

        ,

        , etc. for sections, sub sections, subsub sections. + +.. code-block:: html + +

        PythonClass - Class 6 example

        + +I think that's all you need to know! + + + + + diff --git a/slides_sources/source/homework/index.rst b/_sources/homework/index.txt similarity index 86% rename from slides_sources/source/homework/index.rst rename to _sources/homework/index.txt index 805484dc..2996c733 100644 --- a/slides_sources/source/homework/index.rst +++ b/_sources/homework/index.txt @@ -6,4 +6,5 @@ Homework Materials kata_fourteen html_builder + circle_class diff --git a/slides_sources/source/homework/kata_fourteen.rst b/_sources/homework/kata_fourteen.txt similarity index 95% rename from slides_sources/source/homework/kata_fourteen.rst rename to _sources/homework/kata_fourteen.txt index 8bca7be7..dba1be4d 100644 --- a/slides_sources/source/homework/kata_fourteen.rst +++ b/_sources/homework/kata_fourteen.txt @@ -1,5 +1,6 @@ +========================================= Kata Fourteen: Tom Swift Under Milk Wood -========================================= +========================================= Adapted from Dave Thomas's work: @@ -7,10 +8,15 @@ http://codekata.com/kata/kata14-tom-swift-under-the-milkwood/ +Trigrams +========= Trigrams can be used to mutate text into new, surreal, forms. But what heuristics do we apply to get a reasonable result? +The Problem +------------ + As a boy, one of my treats was go to the shops on a Saturday and spend part of my allowance on books; for a nine-year old, I had quite a collection of Tom Swift and Hardy Boys. Wouldn’t it be great to be able to create @@ -34,8 +40,9 @@ came up with: refused to accept any. As for Mr. Swift as if it goes too high I’ll warn you and you can and swallow frequently. That will make the airship was shooting upward again and just before the raid wouldn’t have been - instrumental in capturing the scoundrels right out of jail." + instrumental in capturing the scoundrels right out of jail." +.. nextslide:: Stylistically, it’s Victor Appleton meets Dylan Thomas. Technically, it’s all done with trigrams. @@ -55,6 +62,8 @@ You might generate:: "may I" => ["wish"] "I may" => ["I"] +.. nextslide:: + This says that the words "I wish" are twice followed by the word "I", the words "wish I" are followed once by "may" and once by "might" and so on. @@ -75,6 +84,8 @@ is constrained to another "I".:: I may I wish I +.. nextslide:: + Now we look up "wish I", and find we have a choice. Let’s choose "may":: @@ -88,6 +99,9 @@ get:: At this point we stop, as no sequence starts "I might." + +.. nextslide:: + Given a short input text, the algorithm isn’t too interesting. Feed it a book, however, and you give it more options, so the resulting output can be surprising. @@ -100,6 +114,9 @@ books (Tom Swift and His Airship is `here `. diff --git a/_sources/include.txt b/_sources/include.txt new file mode 100644 index 00000000..607ee281 --- /dev/null +++ b/_sources/include.txt @@ -0,0 +1,6 @@ + +.. |instructor_1_name| replace:: Christopher Barker +.. |instructor_1_email| replace:: PythonCHB@gmail.com + +.. |instructor_2_name| replace:: Maria McKinley +.. |instructor_2_email| replace:: maria@mariakathryn.net diff --git a/slides_sources/source/index.rst b/_sources/index.txt similarity index 77% rename from slides_sources/source/index.rst rename to _sources/index.txt index f26b9c4e..040d3dfe 100644 --- a/slides_sources/source/index.rst +++ b/_sources/index.txt @@ -1,3 +1,8 @@ +*************** +Intro To Python +*************** + + In This Course ============== @@ -9,7 +14,7 @@ In This Course | .. toctree:: | .. toctree:: | | :maxdepth: 1 | :maxdepth: 1 | | | | - | session01 | homework/index | + | session01 | exercises/index | | session02 | supplements/index | | session03 | | | session04 | | @@ -17,13 +22,15 @@ In This Course | session06 | | | session07 | | | session08 | | + | session09 | | + | session10 | | +----------------------+-----------------------+ .. ifnotslides:: Lectures: --------- - + .. toctree:: :maxdepth: 1 @@ -35,6 +42,8 @@ In This Course session06 session07 session08 + session09 + session10 Materials: ---------- @@ -42,13 +51,16 @@ In This Course .. toctree:: :maxdepth: 2 - homework/index + extra_topics + exercises/index supplements/index .. rst-class:: credit These materials copyright Christopher Barker and Cris Ewing, with thanks to -Jon Jacky and Brian Dorsey for the materials from which these were derived. Licenced under the Creative Commons Attribution-ShareAlike 4.0 International Public License. +Jon Jacky and Brian Dorsey for the materials from which these were derived. +Licenced under the +Creative Commons Attribution-ShareAlike 4.0 International Public License. https://creativecommons.org/licenses/by-sa/4.0/legalcode diff --git a/slides_sources/source/session01.rst b/_sources/session01.txt similarity index 59% rename from slides_sources/source/session01.rst rename to _sources/session01.txt index 8df6ba13..712176d7 100644 --- a/slides_sources/source/session01.rst +++ b/_sources/session01.txt @@ -1,9 +1,16 @@ +.. include:: include.rst + ************************** Session One: Introductions ************************** -| In which you are introduced to this class, your instructors, your environment -| and your new best friend, Python. +Introductions +============= + +In which you are introduced to this class, your instructors, your environment, +and your new best friend, Python. + +| .. image:: /_static/python.png :align: center @@ -15,6 +22,17 @@ Session One: Introductions .. _xkcd.com/353: http://xkcd.com/353 +Goals for Session One: +====================== + +* Meet each other, set expectations for the class. + +* Schedule lightning talks. + +* Get you all up and running with Python + +* Start having fun with Python with a quick tutorial + Introductions ============= @@ -26,38 +44,39 @@ In which we meet each-other Your instructors ---------------- -.. rst-class:: center large +.. rst-class:: center medium -| Christopher Barker -| (PythonCHB at gmail dot com) +| |instructor_1_name| +| |instructor_1_email| | .. nextslide:: -.. rst-class:: center large +.. rst-class:: center medium - -| Dan Hable -| (dhable at gmail dot com) +| |instructor_2_name| +| |instructor_2_email| | Who are you? ------------- -.. rst-class:: center large +.. rst-class:: center medium Tell us a tiny bit about yourself: * name -* programming background -* what do you hope to get from this class +* programming background: what languages have you used? +* neighbor's name +* neighbor's favorite coffee shop or bar + Introduction to This Class ========================== .. rst-class:: center large -Python Programming + Introduction to Python Course Materials Online @@ -65,25 +84,97 @@ Course Materials Online A rendered HTML copy of the slides for this course may be found online at: -http://codefellows.github.io/sea-f2-python-sept14/ +http://uwpce-pythoncert.github.io/IntroToPython + +Also there are some exercise descriptions and supplemental materials. + +The source of these materials are in the class gitHub repo: + +https://github.com/UWPCE-PythonCert/IntroToPython + +We also have a bunch of supplemental resources for the program here: + +http://uwpce-pythoncert.github.io/PythonResources/index.html + +The source for those is here: + +https://github.com/UWPCE-PythonCert/PythonResources + +Class Structure +--------------- + +Class Time: + + * Some lecture -- as little as possible + * Lots of demos + * Lab time: lots of hand-on practice + - Take a break if you need one then... + * Lather, Rinse, Repeat..... + +Interrupt me with questions -- please! + +(Some of the best learning prompted by questions) + +Homework: +--------- + +* Homework will be reading, exercises, and the occasional Video -Also there are homework descriptions and supplemental materials. +* Exercises will be started in class -- but you can finish them at home. + +* You are adults -- it's up to you to do it + +* You can do a gitHub "pull request" if you want us to review your work. + + - We'll show you how to do that in the second session + + +Communication +------------- -The source of these materials are in Chris' gitHub repo: +**Mailing list:** -http://github.com/PythonCHB/codefellows_f2_python +We've set up a Google Group for this class: -Class email list: We will be using this list to communicate for this class: +programming-in-python@googlegroups.com -sea-c25@codefellows.com +We will be using this list to communicate with you. You should have (or will soon) received an email invitation to join the mailing list. + +Slack: We have set up a slack channel for discussions. Anything python related is fair game. + +https://python2016fall.slack.com/ + +We highly encourage you to work together. You will learn at a much deeper level if you work together, +and it gets you ready to collaborate with colleagues. + + +Office Hours +------------ + +We will generally will hold "office hours" at a coffee shop for a couple hours +each weekend. + +Please feel free to attend even if you do not have a specific question. +It is an opportunity to work with the instructors and fellow students, +and learn from each other. + +What are good times for you? + +And what locations? + +Lightning Talks +---------------- -**Canvas**: +**Lightning Talks:** -We will be using Canvas to track your homework submission, but not much else: + * 5 minutes each (including setup) - no kidding! + * Every student will give one + * Purposes: introduce yourself, share interests, show Python applications + * Any topic you like that is related to Python -- according to you! -https://canvas.instructure.com/courses/881467 -You should have received and email invitation to join the class. +Python Ecosystem +================ What is Python? --------------- @@ -95,7 +186,6 @@ What is Python? * Byte-compiled * Interpreted - .. nextslide:: .. rst-class:: center large @@ -106,8 +196,6 @@ But what does that mean? Python Features --------------- -Features: - .. rst-class:: build * Unlike C, C++, C\#, Java ... More like Ruby, Lisp, Perl, Javascript @@ -198,19 +286,18 @@ Python 3.x ("py3k") .. nextslide:: -This class uses Python 2.7 not Python 3.x - -.. rst-class:: build +This class uses Python 3 -- not Python 2 * Adoption of Python 3 is growing fast - * A few key packages still not supported (https://python3wos.appspot.com/) - * Most code in the wild is still 2.x + * Almost all key packages now supported (https://python3wos.appspot.com/) + * But much code in the wild is still 2.x -* You *can* learn to write Python that is forward compatible from 2.x to 3.x -* We will be teaching from that perspective. +* If you find yourself needing to work with Python 2 and 3, there are ways to write compatible code: -* If you find yourself needing to work with Python 2 and 3, there are ways to write compatible code: https://wiki.python.org/moin/PortingPythonToPy3k +https://wiki.python.org/moin/PortingPythonToPy3k + +* We will cover that more later in the program. Also: a short intro to the differences you really need to know about up front later this session. Introduction to Your Environment @@ -218,6 +305,8 @@ Introduction to Your Environment There are three basic elements to your environment when working with Python: +.. rst-class:: left + .. rst-class:: build * Your Command Line @@ -230,70 +319,143 @@ Your Command Line (cli) Having some facility on the command line is important -We won't cover this in class, so if you are not comfortable, please bone up at -home. +We won't cover this much in class, so if you are not comfortable, +please bone up at home. -I suggest running through the **cli** tutorial at "learn code the hard way": +We have some resources here: `PythonResources--command line `_ -`http://cli.learncodethehardway.org/book`_ +**Windows:** -.. _http://cli.learncodethehardway.org/book: http://cli.learncodethehardway.org/book +Most of the demos in class, etc, will be done using the "bash" command line shell on OS-X. This is identical to the bash shell on Linux. +Windows provides the "DOS" command line, which is OK, but pretty old and limited, or "Power Shell" -- a more modern, powerful, flexible command shell. -.. nextslide:: Command Line Enhancements +If you are comfortable with either of these -- go for it. -There are a few things you can do to help make your command line a better place -to work. +If not, you can use the "git Bash" shell -- which is much like the bash shell on OS-X and Linux. -Part of your homework this week will be to do these things. -More on this later. +LAB: Getting set up +------------------- +Before we move on -- we need to get all of us on the same page, with the tools we need for class. -Your Interpreter ----------------- +You will find instructions for how to get python, etc, up and running on your machine here: -Python comes with a built-in interpreter. +**Windows:** -You see it when you type ``python`` at the command line: +http://uwpce-pythoncert.github.io/PythonResources/Installing/python_for_windows.html -.. code-block:: pycon +**OS-X:** - $ python - Python 2.7.5 (default, Aug 25 2013, 00:04:04) - [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin - Type "help", "copyright", "credits" or "license" for more information. - >>> +http://uwpce-pythoncert.github.io/PythonResources/Installing/python_for_mac.html + +**Linux:** + +http://uwpce-pythoncert.github.io/PythonResources/Installing/python_for_linux.html + +We'll run through some of that together. + +If you already have a working environment, please feel free to help your neighbor +or look at the Python Resources pages, particularly reviewing/learning the shell and git. + +http://uwpce-pythoncert.github.io/PythonResources + +Our Class Environment +--------------------- + +We are going to work from a common environment in this class. + +We will take the time here in class to get this going. + +This helps to ensure that you will be able to work. + + +Step 1: Python 3 +------------------ + +.. rst-class:: medium + + Do you already have this?? + +.. code-block:: bash + + $ python + Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25) + [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin + Type "help", "copyright", "credits" or "license" for more information. + >>> + +If not, or you have an older version -- let's install it! -That last thing you see, ``>>>`` is the "Python prompt". +If you're all ready to go -- take this time to get started on a tutorial: -This is where you type code. +http://uwpce-pythoncert.github.io/PythonResources/GeneralPython/learning.html#getting-started-tutorials -.. nextslide:: Python in the Interpreter +Step 2: Pip +----------- + +Python comes with quite a bit ("batteries included"). + +Sometimes you need a bit more. + +Pip allows you to install Python packages to expand your system. + +The previous instructions include pip as well - make sure it's working. + +Once you've installed pip, you use it to install Python packages by name: + +.. code-block:: bash + + $ python -m pip install foobar + ... + +To find packages (and their proper names), you can search the python +package index (PyPI): + +https://pypi.python.org/pypi + + +Step 3: Install iPython +------------------------ + +As this is an intro class, we are going to use almost entirely features +of the standard library. But there are a couple things you may want: + +**iPython** is an "enhanced python shell" -- it make s it easier to work with python interactively. + +.. code-block:: bash + + $ python -m pip install ipython[all] + + +Python in the Interpreter +------------------------- Try it out: -.. code-block:: pycon +.. code-block:: python - >>> print u"hello world!" + >>> print("hello world!") hello world! >>> 4 + 5 9 >>> 2 ** 8 - 1 255 - >>> print u"one string" + u" plus another" + >>> print ("one string" + " plus another") one string plus another >>> .. nextslide:: Tools in the Interpreter -When you are in an interpreter, there are a number of tools available to you. +When you are in an interpreter, there are a number of tools available to +you. There is a help system: -.. code-block:: pycon +.. code-block:: python >>> help(str) Help on class str in module __builtin__: @@ -312,9 +474,9 @@ You can type ``q`` to exit the help viewer. You can also use the ``dir`` builtin to find out about the attributes of a given object: -.. code-block:: pycon +.. code-block:: python - >>> bob = u"this is a string" + >>> bob = "this is a string" >>> dir(bob) ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', @@ -343,8 +505,7 @@ Your Editor Typing code in an interpreter is great for exploring. -But for anything "real", you'll want to save the work you are doing in a more permanent -fashion. +But for anything "real", you'll want to save the work you are doing in a more permanent fashion. This is where an Editor fits in. @@ -365,7 +526,6 @@ characters hidden behind the scenes. .. nextslide:: Minimum Requirements - At a minimum, your editor should have: .. rst-class:: build @@ -379,28 +539,25 @@ In addition, great features to add include: * Tab completion * Code linting -* Jump-to-definition -* Interactive follow-along for debugging Have an editor that does all this? Feel free to use it. -If not, I suggest ``Sublime Text``: +If not, I suggest ``SublimeText``: http://www.sublimetext.com/ -http://www.sublimetext.com/ +(Use version 3, even though it's "beta") +http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/sublime_as_ide.html Why No IDE? ----------- I am often asked this question. -An IDE does not give you much that you can't get with a good editor plus a good -interpreter. +An IDE does not give you much that you can't get with a good editor plus a good interpreter. An IDE often weighs a great deal -Setting up IDEs to work with different projects can be challenging and -time-consuming. +Setting up IDEs to work with different projects can be challenging and time-consuming. Particularly when you are first learning, you don't want too much done for you. @@ -411,163 +568,6 @@ Particularly when you are first learning, you don't want too much done for you. YAGNI -Setting Up Your Environment -=========================== - -.. rst-class:: centered large - -Shared setup means reduced complications. - - -Our Class Environment ---------------------- - -We are going to work from a common environment in this class. - -We will take the time here in class to get this going. - -This helps to ensure that you will be able to work. - - -Step 1: Python 2.7 ------------------- - -.. rst-class:: large - -You have this already, RIGHT? - -.. code-block:: bash - - $ python - Python 2.7.5 (default, Aug 25 2013, 00:04:04) - [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin - Type "help", "copyright", "credits" or "license" for more information. - >>> ^D - $ - -If not: - - * `For the mac <./supplements/python_for_mac.html>`_ - - * `For linux <./supplements/python_for_linux.html>`_ - - * `For windows <./supplements/python_for_windows.html>`_ - -Step 2: Pip ------------ - -Python comes with quite a bit ("batteries included"). - -Sometimes you need a bit more. - -Pip allows you to install Python packages to expand your system. - -You install it by downloading and then executing an installer script: - -.. code-block:: bash - - $ curl -O https://bootstrap.pypa.io/get-pip.py - % Total % Received % Xferd Average Speed Time Time Time Current - Dload Upload Total Spent Left Speed - 100 1309k 100 1309k 0 0 449k 0 0:00:02 0:00:02 --:--:-- 449k - - $ python get-pip.py - -(or go to: http://pip.readthedocs.org/en/latest/installing.html) - -.. nextslide:: Using Pip - -Once you've installed pip, you use it to install Python packages by name: - -.. code-block:: bash - - $ pip install foobar - ... - -To find packages (and their proper names), you can search the python package index (PyPI): - -https://pypi.python.org/pypi - - - -Step 3: Optional -- Virtualenv -------------------------------- - -Python packages come in many versions. - -Often you need one version for one project, and a different one for another. - -`Virtualenv`_ allows you to create isolated environments. - -You can then install potentially conflicting software safely. - -For this class, this is no big deal, but as you start to work on "real" projects, it can be a key tool. - -.. _Virtualenv: http://www.virtualenv.org/ - -If you want to install it, here are some notes: - -`Intro to VirtualEnv <./supplements/virtualenv.html>`_ - - -Step 4: Clone Class Repository ------------------------------- - -`gitHub `_ is an industry-standard system for collaboration on software projects -- particularly open source ones. - -We will use it this class to manage submitting and reviewing your work, etc. - -**Wait!** Don't have a gitHub account? Set one up now. - -Next, you'll make a copy of the class repository using ``git``. - -The canonical copy is in the CodeFellows organization on GitHub: - -https://github.com/codefellows/sea-f2-python-sept14 - -Open that URL, and click on the *Fork* button at the top right corner. - -This will make a copy of this repository in *your* github account. - - -.. nextslide:: Clone Your Fork - -From here, you'll want to make a clone of your copy on your local machine. - -At your command line, run the following commands: - -.. code-block:: bash - - $ cd your_working_directory_for_the_class - $ git clone https://github.com//sea-f2-python-sept14.git - -(you can copy and paste that link from the gitHub page) - -If you have an SSH key set up for gitHub, you'll want to do this instead: - -.. code-block:: bash - - git@github.com:/sea-f2-python-sept14.git - -**Remember**, should be replaced by your github account name. - - -Step 5: Install Requirements ----------------------------- - -As this is an intro class, we are going to use almost entirely features of standand library. But there are a couple things you may want: - -**iPython** - -.. code-block:: bash - - $pip install ipython - -If you are using SublimeText, you may want: - -.. code-block:: bash - - $ pip install PdbSublimeTextSupport Introduction to iPython ======================= @@ -575,7 +575,7 @@ Introduction to iPython iPython Overview ------------------ -You have now installed `iPython`_. +You have installed `iPython`_. iPython is an advanced Python interpreter that offers enhancements. @@ -586,8 +586,8 @@ Specifically, you'll want to pay attention to the information about `Using iPython for Interactive Work`_. .. _iPython: http://ipython.org -.. _official documentation: http://ipython.org/ipython-doc/stable/index.html -.. _Using iPython for Interactive Work: http://ipython.org/ipython-doc/stable/interactive/index.html +.. _official documentation: http://ipython.readthedocs.io/en/stable/ +.. _Using iPython for Interactive Work: http://ipython.readthedocs.io/en/stable/interactive/index.html .. ifslides:: @@ -597,25 +597,22 @@ Specifically, you'll want to pay attention to the information about The very basics of iPython -------------------------- -iPython can do a lot for you, but for starters, here are the key pieces you'll -want to know: +iPython can do a lot for you, but for starters, here are the key pieces +you'll want to know: Start it up .. code-block:: bash - $ipython - - $ ipython - Python 2.7.6 (v2.7.6:3a1db0d2747e, Nov 10 2013, 00:42:54) - Type "copyright", "credits" or "license" for more information. - - IPython 2.0.0 -- An enhanced Interactive Python. - ? -> Introduction and overview of IPython's features. - %quickref -> Quick reference. - help -> Python's own help system. - object? -> Details about 'object', use 'object??' for extra details. + $ ipython + Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19) + Type "copyright", "credits" or "license" for more information. + IPython 4.0.0 -- An enhanced Interactive Python. + ? -> Introduction and overview of IPython's features. + %quickref -> Quick reference. + help -> Python's own help system. + object? -> Details about 'object', use 'object??' for extra details. .. ifslides:: @@ -652,7 +649,7 @@ This is the stuff I use every day: * tab completion: - - ``something.`` + - ``something.`` * running a python file: @@ -661,12 +658,13 @@ This is the stuff I use every day: That's it -- you can get a lot done with those. + How to run a python file -------------------------- A file with python code in it is a 'module' or 'script' -(more on the distiction later on...) +(more on the distinction later on...) It should be named with the ``.py`` extension: ``some_name.py`` @@ -690,15 +688,58 @@ To run it, you have a couple options: [demo] - - Basic Python Syntax =================== +(Follow along in the iPython interpreter...) + .. rst-class:: center mlarge -| Expressions, Statements, -| Values, Types, and Symbols + +| Values, Types, and Names +| +| Expressions and Statements + + +Values +------ + +All of programming is really about manipulating values. + +* Values are pieces of unnamed data: ``42, 'Hello, world',`` + +* In Python, all values are objects + + - Try ``dir(42)`` - lots going on behind the curtain! + +* Every value belongs to a type + + - Try ``type(42)`` - the type of a value determines what it can do + +.. ifslides:: + + .. rst-class:: centered + + [demo] + + +Literals for the Basic Value types: +------------------------------------ + +Numbers: + - floating point: ``3.4`` + - integers: ``456`` + +Text: + - ``"a bit of text"`` + - ``'a bit of text'`` + - (either single or double quotes work -- why?) + +Boolean values: + - ``True`` + - ``False`` + +(There are intricacies to all of these that we'll get into later) Code structure @@ -729,49 +770,28 @@ Statements: In [6]: # statements do not return a value, may contain an expression - In [7]: print u"this" - this + In [7]: line_count = 42 - In [8]: line_count = 42 + In [8]: return something - In [9]: - -.. nextslide:: The Print Statement +.. nextslide:: The Print Function It's kind of obvious, but handy when playing with code: .. code-block:: ipython - In [1]: print u"something" + In [1]: print("something") something -You can print multiple things: +You can print multiple things: .. code-block:: ipython - In [2]: print u"the value is", 5 + In [2]: print("the value is", 5) the value is 5 -.. nextslide:: - -Python automatically adds a newline, which you can suppress with a comma: - - -.. code-block:: ipython - - In [12]: for i in range(5): - ....: print u"the value is", - ....: print i - ....: - the value is 0 - the value is 1 - the value is 2 - the value is 3 - the value is 4 - - .. nextslide:: Any python object can be printed (though it might not be pretty...) @@ -782,7 +802,7 @@ Any python object can be printed (though it might not be pretty...) ...: pass ...: - In [2]: print bar + In [2]: print(bar) @@ -799,7 +819,7 @@ Blocks of code are delimited by a colon and indentation: .. code-block:: python for i in range(100): - print i**2 + print(i**2) .. code-block:: python @@ -810,7 +830,7 @@ Blocks of code are delimited by a colon and indentation: .. nextslide:: -Python uses whitespace to delineate structure. +Python uses indentation to delineate structure. This means that in Python, whitespace is **significant**. @@ -830,12 +850,12 @@ These two blocks look the same: .. code-block:: python for i in range(100): - print i**2 + print(i**2) .. code-block:: python for i in range(100): - print i**2 + print(i**2) .. nextslide:: @@ -861,52 +881,15 @@ But they are not: NEVER INDENT WITH TABS -make sure your editor is set to use spaces only -- - -ideally even when you hit the key - -Values ------- - -.. rst-class:: build - -* Values are pieces of unnamed data: ``42, u'Hello, world',`` -* In Python, all values are objects - - * Try ``dir(42)`` - lots going on behind the curtain! - -* Every value belongs to a type - - * Try ``type(42)`` - the type of a value determines what it can do - -.. ifslides:: - - .. rst-class:: centered +Make sure your editor is set to use spaces only -- - [demo] - -Literals for the Basic Value types: ------------------------------------- +Even when you hit the key -Numbers: - - floating point: ``3.4`` - - integers: ``456`` - -Text: - - ``u"a bit of text"`` - - ``u'a bit of text'`` - - (either single or double quotes work -- why?) -Boolean values: - - ``True`` - - ``False`` - -(There are intricacies to all of these that we'll get into later) - -Values in Action ----------------- +Expressions +------------ -An expression is made up of values and operators +An *expression* is made up of values and operators. .. rst-class:: build @@ -917,12 +900,12 @@ An expression is made up of values and operators * Integer vs. float arithmetic * (Python 3 smooths this out) - * Always use ``/`` when you want float results, ``//`` when you want floored (integer) results + * Always use ``/`` when you want float results, ``//`` when you want + floored (integer) results * Type conversions * This is the source of many errors, especially in handling text - * Python 3 will not implicitly convert bytes to unicode * Type errors - checked at run time only @@ -933,31 +916,31 @@ An expression is made up of values and operators [demo] -Symbols +Names ------- -Symbols are how we give names to values (objects). +Names are how we give names to values (objects) -- hence "names" .. rst-class:: build -* Symbols must begin with an underscore or letter -* Symbols can contain any number of underscores, letters and numbers +* Names must begin with an underscore or letter +* Names can contain any number of underscores, letters and numbers - * this_is_a_symbol + * this_is_a_name * this_is_2 * _AsIsThis * 1butThisIsNot * nor-is-this -* Symbols don't have a type; values do +* Names don't have a type; values do - * This is why python is 'Dynamic' + * This is why python is "Dynamic" -Symbols and Type +Names and Type ---------------- -Evaluating the type of a *symbol* will return the type of the *value* to which +Evaluating the type of a *name* will return the type of the *value* to which it is bound. .. code-block:: ipython @@ -984,7 +967,7 @@ it is bound. Assignment ---------- -A *symbol* is **bound** to a *value* with the assignment operator: ``=`` +A *name* is **bound** to a *value* with the assignment operator: ``=`` .. rst-class:: build @@ -999,10 +982,10 @@ Evaluating the name will return the value to which it is bound .. code-block:: ipython - In [26]: name = u"value" + In [26]: name = "value" In [27]: name - Out[27]: u'value' + Out[27]: 'value' In [28]: an_integer = 42 @@ -1014,6 +997,24 @@ Evaluating the name will return the value to which it is bound In [31]: a_float Out[31]: 3.14 +Variables? +---------- + +.. rst-class:: build + +* In most languages, what I'm calling names are called "variables". + +* In fact, I'll probably call them variables in this class. + +* That's because they are used, for the most part, for the same purposes. + +* But often a "variable" is defined as something like: + "a place in memory that can store values" + +* That is **NOT** what a name in python is! + +* A name can be bound to a value -- but that has nothing to do with a + location in memory. In-Place Assignment ------------------- @@ -1045,7 +1046,8 @@ also: ``-=, *=, /=, **=, \%=`` Multiple Assignment ------------------- -You can assign multiple variables from multiple expressions in one statement +You can assign multiple names from multiple expressions in one +statement .. code-block:: ipython @@ -1068,7 +1070,7 @@ Python evaluates all the expressions on the right before doing any assignments Nifty Python Trick ------------------ -Using this feature, we can swap values between two symbols in one statement: +Using this feature, we can swap values between two names in one statement: .. code-block:: ipython @@ -1086,15 +1088,14 @@ Using this feature, we can swap values between two symbols in one statement: In [55]: j Out[55]: 4 -Multiple assignment and symbol swapping can be very useful in certain contexts - +Multiple assignment and name swapping can be very useful in certain contexts Deleting -------- You can't actually delete anything in python... -``del`` only unbinds a name. +``del`` only deletes a name (or "unbinds" the name...) .. code-block:: ipython @@ -1143,7 +1144,7 @@ Identity Every value in Python is an object. Every object is unique and has a unique *identity*, which you can inspect with -the ``id`` *builtin*: +the ``id`` *builtin* function: .. code-block:: ipython @@ -1162,7 +1163,7 @@ the ``id`` *builtin*: Testing Identity ---------------- -You can find out if the values bound to two different symbols are the **same +You can find out if the values bound to two different names are the **same object** using the ``is`` operator: .. code-block:: ipython @@ -1200,7 +1201,7 @@ You can test for the equality of certain values with the ``==`` operator In [79]: val1 == val2 Out[79]: True - In [80]: val3 = u'50' + In [80]: val3 = '50' In [81]: val1 == val3 Out[84]: False @@ -1230,7 +1231,7 @@ Python Operator Precedence Parentheses and Literals: ``(), [], {}`` - ``"", b'', u''`` + ``"", b'', ''`` Function Calls: ``f(args)`` @@ -1282,36 +1283,37 @@ Anonymous Functions: String Literals --------------- -You define a ``string`` value by writing a *literal*: +A "string" is a chunk of text. + +You define a "string" value by writing a string *literal*: .. code-block:: ipython - In [1]: u'a string' - Out[1]: u'a string' + In [1]: 'a string' + Out[1]: 'a string' - In [2]: u"also a string" - Out[2]: u'also a string' + In [2]: "also a string" + Out[2]: 'also a string' - In [3]: u"a string with an apostrophe: isn't it cool?" - Out[3]: u"a string with an apostrophe: isn't it cool?" + In [3]: "a string with an apostrophe: isn't it cool?" + Out[3]: "a string with an apostrophe: isn't it cool?" - In [4]: u'a string with an embedded "quote"' - Out[4]: u'a string with an embedded "quote"' + In [4]: 'a string with an embedded "quote"' + Out[4]: 'a string with an embedded "quote"' -(what's the '``u``' about?) .. nextslide:: .. code-block:: ipython - In [5]: u"""a multi-line + In [5]: """a multi-line ...: string ...: all in one ...: """ - Out[5]: u'a multi-line\nstring\nall in one\n' + Out[5]: 'a multi-line\nstring\nall in one\n' - In [6]: u"a string with an \n escaped character" - Out[6]: u'a string with an \n escaped character' + In [6]: "a string with an \n escaped character" + Out[6]: 'a string with an \n escaped character' In [7]: r'a "raw" string, the \n comes through as a \n' Out[7]: 'a "raw" string, the \\n comes through as a \\n' @@ -1324,7 +1326,7 @@ Python defines a number of **keywords** These are language constructs. -You *cannot* use these words as symbols. +You *cannot* use these words as names. :: @@ -1338,24 +1340,25 @@ You *cannot* use these words as symbols. .. nextslide:: -If you try to use any of the keywords as symbols, you will cause a + +If you try to use any of the keywords as names, you will cause a ``SyntaxError``: .. code-block:: ipython - In [13]: del = u"this will raise an error" + In [13]: del = "this will raise an error" File "", line 1 - del = u"this will raise an error" + del = "this will raise an error" ^ SyntaxError: invalid syntax .. code-block:: ipython - In [14]: def a_function(else=u'something'): - ....: print else + In [14]: def a_function(else='something'): + ....: print(else) ....: File "", line 1 - def a_function(else=u'something'): + def a_function(else='something'): ^ SyntaxError: invalid syntax @@ -1363,7 +1366,7 @@ If you try to use any of the keywords as symbols, you will cause a __builtins__ ------------ -Python also has a number of pre-bound symbols, called **builtins** +Python also has a number of pre-bound names, called **builtins** Try this: @@ -1384,22 +1387,22 @@ Try this: .. nextslide:: -You are free to rebind these symbols: +You are free to rebind these names: .. code-block:: ipython - In [15]: type(u'a new and exciting string') - Out[15]: unicode + In [15]: type('a new and exciting string') + Out[15]: str - In [16]: type = u'a slightly different string' + In [16]: type = 'a slightly different string' - In [17]: type(u'type is no longer what it was') + In [17]: type('type is no longer what it was') --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () - ----> 1 type(u'type is no longer what it was') + ----> 1 type('type is no longer what it was') - TypeError: 'unicode' object is not callable + TypeError: 'str' object is not callable In general, this is a **BAD IDEA**. @@ -1415,10 +1418,8 @@ There are several exceptions that you are likely to see a lot of: .. rst-class:: build -* ``NameError``: indicates that you have tried to use a symbol that is not bound to - a value. -* ``TypeError``: indicates that you have tried to use the wrong kind of object for - an operation. +* ``NameError``: indicates that you have tried to use a name that is not bound to a value. +* ``TypeError``: indicates that you have tried to use the wrong kind of object for an operation. * ``SyntaxError``: indicates that you have mis-typed something. * ``AttributeError``: indicates that you have tried to access an attribute or method that an object does not have (this often means you have a different @@ -1434,16 +1435,13 @@ What is a function? A function is a self-contained chunk of code - You use them when you need the same code to run multiple times, or in multiple parts of the program. -(DRY) - +(DRY) Or just to keep the code clean - Functions can take and return information .. nextslide:: @@ -1452,8 +1450,8 @@ Minimal Function does nothing .. code-block:: python - def (): - + def a_name(): + a_statement .. nextslide:: @@ -1473,9 +1471,8 @@ Functions: ``def`` .. rst-class:: build * it is executed - * it creates a local variable - - + * it creates a local name + * it does *not* return a value .. nextslide:: function defs must be executed before the functions can be called: @@ -1493,7 +1490,7 @@ function defs must be executed before the functions can be called: .. code-block:: ipython In [18]: def simple(): - ....: print u"I am a simple function" + ....: print("I am a simple function") ....: In [19]: simple() @@ -1514,17 +1511,17 @@ You **call** a function using the function call operator (parens): In [4]: simple() I am a simple function +Calling a function is how you run the code in that function. Functions: Call Stack --------------------- -functions call functions -- this makes an execution stack -- that's all a trace -back is +functions call functions -- this makes an execution stack -- that's all a trace back is .. code-block:: ipython In [5]: def exceptional(): - ...: print u"I am exceptional!" + ...: print("I am exceptional!") ...: print 1/0 ...: In [6]: def passive(): @@ -1558,8 +1555,8 @@ Functions: Tracebacks in exceptional() 1 def exceptional(): - 2 print u"I am exceptional!" - ----> 3 print 1/0 + 2 print("I am exceptional!") + ----> 3 print(1/0) 4 ZeroDivisionError: integer division or modulo by zero @@ -1580,7 +1577,7 @@ This is actually the simplest possible function: .. nextslide:: -if you don't explicilty put ``return`` there, Python will: +if you don't explicitly put ``return`` there, Python will return None for you: .. code-block:: ipython @@ -1589,15 +1586,15 @@ if you don't explicilty put ``return`` there, Python will: ...: In [10]: fun() In [11]: result = fun() - In [12]: print result + In [12]: print(result) None -note that the interpreter eats ``None`` +note that the interpreter eats ``None`` -- you need to call ``print()`` to see it. .. nextslide:: -Only one return statement will ever be executed. +Only one return statement in a function will ever be executed. Ever. @@ -1608,12 +1605,12 @@ This is useful when debugging! .. code-block:: ipython In [14]: def no_error(): - ....: return u'done' + ....: return 'done' ....: # no more will happen - ....: print 1/0 + ....: print(1/0) ....: In [15]: no_error() - Out[15]: u'done' + Out[15]: 'done' .. nextslide:: @@ -1654,10 +1651,10 @@ In a ``def`` statement, the values written *inside* the parens are In [22]: def fun(x, y, z): ....: q = x + y + z - ....: print x, y, z, q + ....: print(x, y, z, q) ....: -x, y, z are *local* symbols -- so is q +x, y, z are *local* names -- so is q Functions: arguments @@ -1671,24 +1668,24 @@ When you call a function, you pass values to the function parameters as In [23]: fun(3, 4, 5) 3 4 5 12 -The values you pass in are *bound* to the symbols inside the function and used. +The values you pass in are *bound* to the names inside the function and used. The ``if`` Statement --------------------- -In order to do anything interesting at all (including this week's homework), you need to be able to make a decision. +In order to do anything interesting at all, you need to be able to make a decision. .. nextslide:: -.. code-block:: python +.. code-block:: ipython In [12]: def test(a): ....: if a == 5: - ....: print u"that's the value I'm looking for!" + ....: print("that's the value I'm looking for!") ....: elif a == 7: - ....: print u"that's an OK number" + ....: print("that's an OK number") ....: else: - ....: print u"that number won't do!" + ....: print("that number won't do!") In [13]: test(5) that's the value I'm looking for! @@ -1710,48 +1707,93 @@ That's it for our basic intro to Python Before next session, you'll use what you've learned here today to do some exercises in Python programming +Schedule the lightning talks: +----------------------------- -Homework -======== +.. rst-class:: build -Four Tasks by Next Monday +* We need to schedule your lightning talks. +* **Let's use Python for that !** -Task 1 ------- +[demo] -**Tell Us About Yourself** +Python 2-3 Differences +====================== -This is a way for you to learn a bit about gitHub, and how you are going to submit most of your homework. +Much of the example code you'll find online is Python2, rather than Python3 -* Create a new folder in the ``students`` folder in the class repository. +For the most part, they are the same -- so you can sue those examples to learn from. - * Create the folder in your clone of your fork of the repository. - * Name it with your own name in CamelCase, like: ``ChrisBarker``. - * In the folder create one new file, named ``README.md`` - * In that new file, write up a few paragraphs about yourself. +There are a lot of subtle differences that you don't need to concern yourself with just yet. - * Use proper `markdown`_ syntax. (or `reStructuredText`_) - * Include at least two headings, of different levels. - * Include at least one link. +But a couple that you'll need to know right off the bat: -.. _markdown: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet +print() +------- -.. _reStructuredText: http://docutils.sourceforge.net/rst.html +In python2, ``print`` is a "statement", rather than a function. That means it didn't require parenthes around what you want printed:: -.. nextslide:: + print something, something_else -* Using ``git add``, add the new folder and file to your clone of the - repository. -* Using ``git commit``, commit your changes to your clone (write a good commit - message). If you later edit your file, don't forget to commit those changes - too. -* Using ``git push``, push your commits to your fork on GitHub. -* In GitHub's Web UI, make a ``pull request`` to the original CodeFellows - repository. +This made it a bit less flexible and powerful. +But -- if you try to use it that way in Python3, you'll get an error:: -Task 2 + In [15]: print "this" + File "", line 1 + print "this" + ^ + SyntaxError: Missing parentheses in call to 'print' + +So -- if you get this error, simply add the parentheses:: + + In [16]: print ("this") + this + +.. nextslide:: division + +In python 3, the divsion operator is "smart" when you divide integers:: + + In [17]: 1 / 2 + Out[17]: 0.5 + +However in python2, integer division, will give you an integer result:: + + In [1]: 1/2 + Out[1]: 0 + +In both versions, you can get "integer division" if you want it with a double slash:: + + In [1]: 1//2 + Out[1]: 0 + +And in python2, you can get the behavior of py3 with "true division":: + + In [2]: from __future__ import division + + In [3]: 1/2 + Out[3]: 0.5 + +For the most part, you just need to be a bit careful with the rare cases where py2 code counts on integer division. + +Other py2/py3 differences +------------------------- + +Most of the other differences are essentially of implementation details, like getting iterators instead of sequences -- we'll talk about that more when it comes up in class. + +There are also a few syntax differences with more advances topics: Exceptions, super(), etc. + +We'll talk about all that when we cover those topics. + + +Homework +======== + +Tasks and reading by next week + + +Task 1 ------ **Set Up a Great Dev Environment** @@ -1759,96 +1801,128 @@ Task 2 Make sure you have the basics of command line usage down: Work through the supplemental tutorials on setting up your -`Command Line`_ for good development support. +Command Line (http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/shell.html) for good development support. -Make sure you've got your editor set up productively -- at the very very least, make sure it does Python indentation well. +Make sure you've got your editor set up productively -- at the very very +least, make sure it does Python indentation and syntax coloring well. + +.. nextslide:: **Advanced Editor Setup:** If you are using SublimeText, here are some notes to make it super-nifty: -Setting up `SublimeText`_ . +http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/sublime_as_ide.html At the end, your editor should support tab completion and pep8 and pyflakes -linting. Your command line should be able to show you what virtualenv is active -and give you information about your git repository when you are inside one. +linting. If you are not using SublimeText, look for plugins that accomplish the same goals for your own editor. If none are available, please consider a change of editor. -.. _SublimeText: supplements/sublime_as_ide.html -.. _Command Line: supplements/shell.html +Also make sure you've got iPython working, if you didn't get to that in class. + Task 3 ------ +**Explore Errors** + +* Create a new directory in your working dir for the class:: + + $ mkdir session01 + $ cd session01 + +* Add a new file to it called ``break_me.py`` + +* In the ``break_me.py`` file write four simple Python functions: + + * Each function, when called, should cause an exception to happen + + * Each function should result in one of the four common exceptions from our + lecture. + + * for review: ``NameError``, ``TypeError``, ``SyntaxError``, ``AttributeError`` + +(hint -- the interpreter will quit when it hits a Exception -- so you can comment out all but the one you are testing at the moment) + + * Use the Python standard library reference on `Built In Exceptions`_ as a + reference + +.. _Built In Exceptions: https://docs.python.org/3/library/exceptions.html + +Task 2 +------ + **Python Pushups** To get a bit of exercise solving some puzzles with Python, work on the Python -exercises at `CodingBat`_. +exercises at "Coding Bat": http://codingbat.com/python -Begin by making an account on the site. Once you have done so, go to the -'prefs' link at the top right and enter your name so we know who you are. +There are 8 sets of puzzles. Do as many as you can, but try to at least +get all the "Warmups" done. -In addition, add the following email address to the 'Share To' box. This will -allow your instructors to see the work you have done. -:: +Reading, etc. +------------- - pyinstructor@codefellows.com +Every one of you has a different backgrond and learning style. -There are 8 sets of puzzles. Do as many as you can, starting with the Warmups. +So take a bit of time to figure out which resource works for you. -.. _CodingBat: http://codingbat.com +http://uwpce-pythoncert.github.io/PythonResources/GeneralPython/learning.html -**Please Note:** Do Not send emails to the above email address, they will not -be answered. +provides some options. Do look it over. +But here are few to get you started this week: -Task 4 ------- +*Think Python:* Chapters 1–7 (http://greenteapress.com/wp/think-python-2e/) -**Explore Errors** +*Dive Into Python:* Chapters 1–2 (http://www.diveintopython3.net/) -* Create a new directory in your personal folder in the ``students`` folder of the class repository:: - - $ mkdir session01 - $ cd session01 +*LPTHW:* ex. 1–10, 18-21 (http://learnpythonthehardway.org/book/) -* Make sure you create it in your clone of your fork of the repository. +*NOTE:* LPTHW is python 2 -- you will need to add parentheses to all your print calls! -* Add a new file to it called ``break_me.py`` +Or follow this excellent introductory tutorial: -* Use ``git add`` to add the file to the repository. +https://www.youtube.com/watch?v=MirG-vJOg04 -.. nextslide:: +You should be comfortable with working with variables, numbers, strings, and basic functions. -* In the ``break_me.py`` file write four simple Python functions: +git +--- - * Each function, when called, should cause an exception to happen - * Each function should result in one of the four common exceptions from our - lecture. +We'll be covering the basics of git next week - enough to use for this class. Please read one of these so you'll have a head start: - * for review: ``NameError``, ``TypeError``, ``SyntaxError``, ``AttributeError`` +http://rogerdudler.github.io/git-guide/ -(hint -- the interpreter will quit when it hits a Exception -- so you can comment out all but the one you are testing at the moment) +or - * Use the Python standard library reference on `Built In Exceptions`_ as a - reference +https://try.github.io/levels/1/challenges/1 -.. nextslide:: -* Use ``git commit`` to commit changes you make to your clone +Next Class +=========== + +Next week, we'll: + + * get set up with git and gitHub + * Some more basic Python + * More on Functions + * Boolean Expressions + * Code Structure, Modules, and Namespaces + + +Office Hours +------------ + +We will have office hours on either Saturday or Sunday from 10:00 to noon. - * Make frequent, small commits using ``git commit`` when working. - * Write clear, concise commit messages that explain what you are doing. +Preferences? -* When you are finished with your work, use ``git push`` to push your changes - to your fork on GitHub. +Locations? -* Finally, issue a pull request to the original CodeFellows repository with - your work. -.. _Built In Exceptions: https://docs.python.org/2/library/exceptions.html diff --git a/slides_sources/source/session02.rst b/_sources/session02.txt similarity index 55% rename from slides_sources/source/session02.rst rename to _sources/session02.txt index b51b55c5..a5199d68 100644 --- a/slides_sources/source/session02.rst +++ b/_sources/session02.txt @@ -1,22 +1,13 @@ -******************************************** -Session Two: Functions, Booleans and Modules -******************************************** - -.. ifslides:: - - .. rst-class:: center large - - Oh My! - +.. include:: include.rst +**************************************************** +Session Two: gitHub, Functions, Booleans and Modules +**************************************************** Review/Questions ================ -Review of Previous Session --------------------------- - -.. rst-class:: build +.. rst-class:: left medium * Values and Types * Expressions @@ -27,69 +18,321 @@ Homework Review .. rst-class:: center large -Any questions that are nagging? + Any questions that are nagging? +Lightning Talks Today: +---------------------- -Git Work -======== +.. rst-class: medium -.. rst-class:: center large -Let's get to know your fellow students! +| +| David E Tobey +| +| Sharmila Muralidharan +| +| Shu A Latif +| +| Spencer G McGhin + +Class Outline +------------- + + * git / gitHub primer + * Exercise: :ref:`exercise_grid_printer` + * Decisions, Decisions. + * Exercise: :ref:`exercise_fizz_buzz` + * More on functions + * Exercise: :ref:`exercise_fibonacci` + * Boolean Expressions + * Code Structure, Modules, and Namespaces +First a little git Primer... +============================== + +Let's get to know git a bit + + +Why Version Control? +-------------------- + +.. figure:: /_static/phd101212s.gif + :class: fill + :width: 45 % + +.. ifnotslides:: + + "Piled Higher and Deeper" by Jorge Cham + + www.phdcomics.com + +What is git? +------------ +.. rst-class:: build -Working with an Upstream ------------------------- +.. container:: -You've created a fork of the class repository from the ``codefellows`` account -on GitHub. + A "version control system" -You've pushed your own changes to that fork, and then issued pull requests to -have that worked merged back to the ``codefellows`` original. + A history of everything everyone does to 'your' code -You want to keep your fork up-to-date with that original copy as the class goes -forward. + A graph of "states" in which the code has existed -To do this, you use the git concept of an **upstream** repository. + That last one is a bit tricky, and is not necessary to understand right out of the gate. When you are ready, you can look at this supplement to gain a better understanding: + + :ref: http://uwpce-pythoncert.github.io/PythonResources/DevEnvironment/git_overview.html + +Setting up git +-------------- + +You should have git installed on your machine and accessible from the command line. There will be a little bit of setup for git that you should only have to do once. + +.. code-block:: bash + + $ git config --global user.name "Marie Curie" + $ git config --global user.email "marie@radioactive.com" + +Editor +------ + +* git needs an editor occasionally +* default is VI, which is not very intuitive to non-Unix Geeks +* Nano is simple, easy solution for Macs and Linux +* Nano no longer available for windows, use Sublime or Notepad++ + + +For Windows users: + http://uwpce-pythoncert.github.io/PythonResources/Installing/git_editor_windows.html .. nextslide:: +Once you have chosen/installed an editor, configure git to use it: + +nano +``$ git config --global core.editor "nano -w"`` + +sublime (mac) +``$ git config --global core.editor "subl -n -w"`` + +sublime (win) +``$ git config --global core.editor "'c:/program files/sublime text 2/sublime_text.exe' -w"`` + +Notepad++ (Win) +``$ git config --global core.editor "'c:/program files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"`` + +Repositories +------------ + +A repository is just a collection of files that 'belong together'. + Since ``git`` is a *distributed* versioning system, there is no **central** -repository that serves as the one to rule them all. +repository that serves as the one to rule them all. This simply means that all repositories should look the same. -Instead, you work with *local* repositories, and *remotes* that they are -connected to. +However, to keep things sane, there is generally one "central" repository chosen that users check with for changes, for us this is GitHub. -Cloned repositories get an *origin* remote for free: -.. code-block:: bash +Working with Remotes +-------------------- + +With git, you work with *local* repositories and *remotes* that they are connected to. + +.. rst-class:: build +.. container:: + + Git uses shortcuts to address *remotes*. Cloned repositories get an *origin* shortcut for free: + + .. code-block:: bash + + $ git remote -v + origin https://github.com/UWPCE-PythonCert/IntroPython2016.git (fetch) + origin https://github.com/UWPCE-PythonCert/IntroPython2016.git (push) + + This shows that the local repo on my machine *originated* from the one in + the UWPCE-PythonCert gitHub account (it shows up twice, because I there is + a shortcut for both fetch from and push to this remote) + +.. nextslide:: + +.. rst-class:: build +.. container:: + + You can work on any project you wish to that has a public repository on Github. However, since you won't have permission to edit most projects directly, there is such a thing as *forking* a project. + + When you *fork* a repository, you make a copy of that repository in your own (Github) account. + + When you have made changes that you believe the rest of the community will want to adopt, you make a *pull request* to the original project. The maintainer(s) of that project than have the option of accepting your changes, in which case your changes will become part of that project. + + This is how we will be working in this class. When you want feedback on your work, you will make a *pull request* to the instructors. + +.. nextslide:: + +Our class materials reside in a repository on *Github* in the *UWPCE-PythonCert* organization: + +.. figure:: /_static/remotes_start.png + :width: 50% + :class: center + +.. nextslide:: + +Note that this is not the same repository as the class materials. + +It will be a repository that is created just for this class, and will be called IntroPython*quarter*. + +In examples below it is called IntroToPython, so replace that in your head with the name of this year's repository. :) + +We will create this repository now. + +.. nextslide:: + +This new repository will include examples and we will add relevant materials (and exercise solutions) to it throughout the quarter. + +There will be a folder called students at the top level, and everyone will create their own directory within it. + +So, everyone will commit to this repository, and everyone will have access to everyone's code. + +This will make it easier to collaborate. + +We will do a live demo of setting up a machine now. + +.. nextslide:: + +We will now create a fork of the class repository from the ``UWPCE-PythonCert`` +account on GitHub into your personal account. This is done on the GitHub website. + +Let's pause now to let you all create a gitHub account if you don't have one already. + +.. figure:: /_static/remotes_fork.png + :width: 50% + :class: center + +.. nextslide:: + +The next step is to make a *clone* of your fork on your own computer, which means that **your fork** in github is the *origin* (Demo): - $ git remote -v - origin https://github.com/PythonCHB/sea-f2-python-sept14.git (fetch) - origin https://github.com/PythonCHB/sea-f2-python-sept14.git (push) +.. figure:: /_static/remotes_clone.png + :width: 50% + :class: center -This shows that the local repo on my machine *originated* from the one in my gitHub account (the one it was cloned from) +.. nextslide:: + +We will now set up our individual folders and include a README in this folder. + + +.. rst-class:: build +.. container:: + + .. code-block:: bash + + $ cd IntroPythonXXXX + $ git status + + .. code-block:: bash + + $ git pull origin master + + .. code-block:: bash + + $ cd students + + .. code-block:: bash + + $ mkdir maria_mckinley + + .. code-block:: bash + + $ cd maria_mckinley + + .. code-block:: bash + + $ echo "# Python code for UWPCE-PythonCert class" >> README.rst + +.. nextslide:: + +.. rst-class:: build +.. container:: + + Check the status + + .. code-block:: bash + + $ git status + + Add anything you want to commit to your commit: + + .. code-block:: bash + + $ git add README.rst + + Make your commit: + + .. code-block:: bash + + $ git commit -m 'added a readme file' + + +.. nextslide:: + +Push your changes: + + .. code-block:: bash + + $ git push origin master + + origin is the default name given by git refering to the server you cloned + (in this case your github repository) + + master is the branch that you are currently pushing to that server + + Go onto GitHub, and make a pull request! + + (This will be a pull request from a fork rather than from a branch) + + https://help.github.com/articles/creating-a-pull-request-from-a-fork/ + + +.. nextslide:: + +You've pushed your own changes to that fork, and then issued pull requests to have that work merged back to the ``UWPCE-PythonCert`` original. + +.. rst-class:: build +.. container:: + + You want to keep your fork up-to-date with that original copy as the class + goes forward. + + To do this, you add a new *remote* repository to your local clone. .. nextslide:: Adding a Remote You can add *remotes* at will, to connect your *local* repository to other copies of it in different remote locations. -This allows you to grab changes made to the repository in these other -locations. +.. rst-class:: build +.. container:: -For our class, we will add an *upstream* remote to our local copy that points -to the original copy of the material in the ``codefellows`` account. + This allows you to grab changes made to the repository in these other + locations. -.. code-block:: bash + For our class, we will add an *upstream* remote to our local copy that points to the original copy of the material in the ``UWPCE-PythonCert`` account, and we will call it, appropriately, "upstream" + + .. code-block:: bash - $ git remote add upstream https://github.com/codefellows/sea-f2-python-sept14.git + $ git remote add upstream https://github.com/UWPCE-PythonCert/IntroPython2015.git + + $ git remote -v + origin https://github.com/PythonCHB/IntroPython2015.git (fetch) + origin https://github.com/PythonCHB/IntroPython2015.git (push) + upstream https://github.com/UWPCE-PythonCert/IntroPython2015.git (fetch) + upstream https://github.com/UWPCE-PythonCert/IntroPython2015.git (push) + +.. nextslide:: + +This should leave you in a situation that looks like this: + +.. figure:: /_static/remotes_upstream.png + :width: 50% + :class: center - $ git remote -v - origin https://github.com/PythonCHB/sea-f2-python-sept14.git (fetch) - origin https://github.com/PythonCHB/sea-f2-python-sept14.git (push) - upstream https://github.com/codefellows/sea-f2-python-sept14.git (fetch) - upstream https://github.com/codefellows/sea-f2-python-sept14.git (push) .. nextslide:: Fetching Everything. @@ -109,13 +352,9 @@ Then you can see the branches you have locally available: $ git branch -a * master remotes/origin/HEAD -> origin/master - remotes/origin/gh-pages remotes/origin/master - remotes/upstream/gh-pages remotes/upstream/master -(the gh-pages branch is used to publish these notes) - .. nextslide:: Fetching Upstream Changes Finally, you can fetch and then merge changes from the upstream master. @@ -126,20 +365,16 @@ Start by making sure you are on your own master branch: $ git checkout master -This is **really really** important. Take the time to ensure you are where you -think you are. +This is **really really** important. Take the time to ensure you are where you think you are, iow, not on a remote. Use git status to find out where you are, if necesary. .. nextslide:: Merging Upstream Changes -Then, fetch the upstream master branch and merge it into your master: +Then, fetch the upstream master branch and merge it into your master. +You can do this in one step with: .. code-block:: bash - $ git fetch upstream master - From https://github.com/codefellows/sea-f2-python-sept14 - * branch master -> FETCH_HEAD - - $ git merge upstream/master + $ git pull upstream master Updating 3239de7..9ddbdbb Fast-forward Examples/README.rst | 4 ++++ @@ -147,15 +382,11 @@ Then, fetch the upstream master branch and merge it into your master: create mode 100644 Examples/README.rst ... -NOTE: you can do that in one step with: - -.. code-block:: bash - - $ git pull upstream master .. nextslide:: Pushing to Origin Now all the changes from *upstream* are present in your local clone. +You should do this pull everytime you start to work on code. In order to preserve them in your fork on GitHub, you'll have to push: @@ -176,93 +407,152 @@ In order to preserve them in your fork on GitHub, you'll have to push: You can incorporate this into your daily workflow: :: + [make sure you are on correct branch] $ git checkout master + [get any changes from class repository] $ git pull upstream master - $ git push - [do some work] - $ git commit -a + [make sure you are in your student directory, do work] + [verify you are happy with changes] + $ git status + [add your changes to what will be committed] + $ git add . [add a good commit message] + $ git commit -m 'I wrote some Python.' + [push your changes to your remote github account] $ git push - [make a pull request] + [make a pull request on the GitHub website] -Quick Intro to Basics -===================== -.. rst-class:: center large +.. nextslide:: Note + +Because of the way we have set up the class, you will be able +to see all work submitted to us from everyone in the class in +the students directory on your machine. This is not a bad thing. +And the files tend to be small. + +We encourage sharing of knowledge in this class. Helping your +fellow students will also help you to better understand. Share +your code, and get use to giving/receiving feedback on how to +improve your code, if you are not already. + + +LAB: Grid Printer +================= + +.. rst-class:: left + + With only the ability to do a bit with numbers and text, you should be + able to do this little project: + + :ref:`exercise_grid_printer` + +Getting Started: +---------------- + +Lets use git and gitHub to manage this project: + +Start by putting a python file in your clone of the class gitHub project: + +.. code-block:: bash + + $ cd my_personal_directory + $ mkdir session_02 + $ cd session_02 + $ touch grid_printer.py + $ git add grid_printer.py + +Then put your code in grid_printer.py + +Committing your code +-------------------- + +When your code does something useful, you can commit it. + +First check the status: + +.. code-block:: bash + + $ git status + +If it's what you expect, you can commit and push: + +.. code-block:: bash + + $ git commit -a -m "first version" + $ git push + +And when you want us to take a look, you can go to gitHub and do a "Pull Request" +(make sure you commit and push first) + + +Committing your code +-------------------- + +Commit early and often. + + +Lightning Talk: +--------------- + +.. rst-class:: center medium + +David E Tobey + + +Beyond Printing +================ + +.. rst-class:: center medium Because there's a few things you just gotta have Basics ------ -It turns out you can't really do much at all without at least a container type, -conditionals and looping... +You really can't really do much at all without at least +conditionals, looping, and a container type... -.. nextslide:: if +Making a Decision +------------------ -``if`` and ``elif`` allow you to make decisions: +**"Conditionals"** + +``if`` and ``elif`` (else if) allow you to make decisions: .. code-block:: python if a: - print 'a' + print('a') elif b: - print 'b' + print('b') elif c: - print 'c' + print('c') else: - print 'that was unexpected' + print('that was unexpected') .. nextslide:: if -What's the difference between these two: +What's the difference between these two? .. code-block:: python if a: - print 'a' + print('a') elif b: - print 'b' + print('b') + ## versus... if a: - print 'a' + print('a') if b: - print 'b' - - -.. nextslide:: switch? - -Many languages have a ``switch`` construct: + print('b') -.. code-block:: js - switch (expr) { - case "Oranges": - document.write("Oranges are $0.59 a pound.
        "); - break; - case "Apples": - document.write("Apples are $0.32 a pound.
        "); - break; - case "Mangoes": - case "Papayas": - document.write("Mangoes and papayas are $2.79 a pound.
        "); - break; - default: - document.write("Sorry, we are out of " + expr + ".
        "); - } -.. nextslide:: switch? - -**Not Python** - -use ``if..elif..elif..else`` - -(or a dictionary, or subclassing....) - - -.. nextslide:: lists +Lists +----- A way to store a bunch of stuff in order @@ -273,8 +563,10 @@ Pretty much like an "array" or "vector" in other languages a_list = [2,3,5,9] a_list_of_strings = ['this', 'that', 'the', 'other'] +You can put any type of object in a list... -.. nextslide:: tuples +Tuples +------- Another way to store an ordered list of things @@ -283,24 +575,27 @@ Another way to store an ordered list of things a_tuple = (2,3,4,5) a_tuple_of_strings = ('this', 'that', 'the', 'other') +You can also put any type of object in a tuple... +(sense a theme here?) Tuples are **not** the same as lists. The exact difference is a topic for next session. -.. nextslide:: for +``for`` loops +-------------- Sometimes called a 'determinate' loop -When you need to do something to everything in a sequence +When you need to do something to all the objects in a sequence .. code-block:: ipython In [10]: a_list = [2,3,4,5] In [11]: for item in a_list: - ....: print item + ....: print(item) ....: 2 3 @@ -308,24 +603,26 @@ When you need to do something to everything in a sequence 5 -.. nextslide:: range() and for +``range()`` and for +------------------- -Range builds lists of numbers automatically +``range`` builds sequences of numbers automatically Use it when you need to do something a set number of times .. code-block:: ipython - In [12]: range(6) - Out[12]: [0, 1, 2, 3, 4, 5] - - In [13]: for i in range(6): - ....: print "*", + In [31]: for i in range(4): + print('*', end=' ') ....: - * * * * * * + * * * * + +NOTE: ``range(n)`` creates an "iterable" -- something you can loop over +-- more on that later. -.. nextslide:: Intricacies +Intricacies +------------ This is enough to get you started. @@ -334,28 +631,47 @@ Each of these have intricacies special to python We'll get to those over the next couple of classes -Functions -========= +LAB: Fizz Buzz +=============== -Review ------- +.. rst-class:: left + + We now have the tools to do a implementation of the classic "Fizz Buzz" problem: + + :ref:`exercise_fizz_buzz` + + Do the same git / gitHub dance with this, too! + + +Lightning Talk: +--------------- + +.. rst-class:: center medium + +Sharmila Muralidharan + + +More on Functions +================= + +Variable scope +-------------- Defining a function: .. code-block:: python def fun(x, y): - z = x+y + z = x + y return z - x, y, z are *local* names Local vs. Global ---------------- -Symbols bound in Python have a *scope* +Names bound in Python have a *scope* That *scope* determines where a symbol is visible, or what value it has in a given block. @@ -366,7 +682,7 @@ given block. In [15]: y = 33 In [16]: z = 34 In [17]: def fun(y, z): - ....: print x, y, z + ....: print(x, y, z) ....: In [18]: fun(3, 4) 32 3 4 @@ -390,8 +706,8 @@ But, did the value of y and z change in the *global* scope? In general, you should use global bindings mostly for constants. -In python we designate global constants by typing the symbols we bind to them -in ALL_CAPS +The python convention is to designate global constants by typing the +symbols we bind to them in ALL_CAPS .. code-block:: python @@ -402,7 +718,8 @@ in ALL_CAPS This is just a convention, but it's a good one to follow. -.. nextslide:: Global Gotcha +Global Gotcha +-------------- Take a look at this function definition: @@ -413,8 +730,8 @@ Take a look at this function definition: In [22]: def f(): ....: y = x ....: x = 5 - ....: print x - ....: print y + ....: print(x) + ....: print(y) ....: What is going to happen when we call ``f`` @@ -425,18 +742,18 @@ Try it and see: .. code-block:: ipython - In [23]: f() + In [34]: f() --------------------------------------------------------------------------- UnboundLocalError Traceback (most recent call last) - in () + in () ----> 1 f() - in f() + in f() 1 def f(): ----> 2 y = x 3 x = 5 - 4 print x - 5 print y + 4 print(x) + 5 print(y) UnboundLocalError: local variable 'x' referenced before assignment @@ -452,7 +769,7 @@ So far we've seen simple parameter lists: .. code-block:: python def fun(x, y, z): - print x, y, z + print(x, y, z) These types of parameters are called *positional* @@ -467,7 +784,7 @@ You can provide *default values* for parameters in a function definition: .. code-block:: ipython In [24]: def fun(x=1, y=2, z=3): - ....: print x, y, z + ....: print(x, y, z) ....: When parameters are given with default values, they become *optional* @@ -511,29 +828,6 @@ provide any *positional* arguments: fun(x=5, 6) SyntaxError: non-keyword arg after keyword arg -.. nextslide:: Parameters and Unpacking - -This brings us to a fun feature of Python function definitions. - -You can define a parameter list that requires an **unspecified** number of -*positional* or *keyword* arguments. - -The key is the ``*`` (splat) or ``**`` (double-splat) operator: - -.. code-block:: ipython - - In [31]: def fun(*args, **kwargs): - ....: print args, kwargs - ....: - In [32]: fun(1) - (1,) {} - In [33]: fun(1, 2, zombies="brains") - (1, 2) {'zombies': 'brains'} - In [34]: fun(1, 2, 3, zombies="brains", vampires="blood") - (1, 2, 3) {'vampires': 'blood', 'zombies': 'brains'} - -**args** and **kwargs** are *conventional* names for these. - Documentation ------------- @@ -547,8 +841,6 @@ This can help reduce the number of `WTFs per minute`_ in reading it later. There are two approaches to this: -.. rst-class:: build - * Comments * Docstrings @@ -568,11 +860,11 @@ You can use them to mark places you want to revisit later: .. code-block:: python for partygoer in partygoers: - for baloon in baloons: + for balloon in balloons: for cupcake in cupcakes: # TODO: Reduce time complexity here. It's killing us # for large parties. - resolve_party_favor(partygoer, baloon, cupcake) + resolve_party_favor(partygoer, balloon, cupcake) .. nextslide:: Comments @@ -590,10 +882,12 @@ This is not useful: # apply soap to each sponge worker.apply_soap(sponge) -.. nextslide:: Docstrings +Note: Nothing special about Python here -- basic good programing practice. + +Docstrings +---------- -In Python, ``docstrings`` are used to provide in-line documentation in a number -of places. +In Python, ``docstrings`` are used to provide in-line documentation in a number of places. The first place we will see is in the definition of ``functions``. @@ -611,24 +905,23 @@ header, it is a ``docstring``: You can then read this in an interpreter as the ``__doc__`` attribute of the function object. -.. nextslide:: Docstrings +.. nextslide:: A ``docstring`` should: -.. rst-class:: build -* be a complete sentence in the form of a command describing what the function +* Be a complete sentence in the form of a command describing what the function does. * """Return a list of values based on blah blah""" is a good docstring * """Returns a list of values based on blah blah""" is *not* -* fit onto a single line. +* Have a useful single line. * If more description is needed, make the first line a complete sentence and add more lines below for enhancement. -* be enclosed with triple-quotes. +* Be enclosed with triple-quotes. * This allows for easy expansion if required at a later date * Always close on the same line if the docstring is only one line. @@ -658,8 +951,7 @@ Recursion is especially useful for a particular set of problems. For example, take the case of the *factorial* function. -In mathematics, the *factorial* of an integer is the result of multiplying that -integer by every integer smaller than it down to 1. +In mathematics, the *factorial* of an integer is the result of multiplying that integer by every integer smaller than it down to 1. :: @@ -673,26 +965,46 @@ We can use a recursive function nicely to model this mathematical function [demo] +``assert`` +---------- -In-Class Lab: -============= +Writing ``tests`` that demonstrate that your program works is an important part of learning to program. -.. rst-class:: center large +The python ``assert`` statement is useful in writing simple tests +for your code. -Fun With Functions +.. code-block:: ipython -Exercises ---------- + In [1]: def add(n1, n2): + ...: return n1 + n2 + ...: -Try your hand at writing a function that computes the distance between two -points:: + In [2]: assert add(3, 4) == 7 - dist = sqrt( (x1-x2)**2 + (y1-y2)**2 ) + In [3]: assert add(3, 4) == 10 -Experiment with ``locals`` by adding this statement to the function you just -wrote::: + --------------------------------------------------------------------- + AssertionError Traceback (most recent call last) + in () + ----> 1 assert add(3, 4) == 10 - print locals() + AssertionError: + + +LAB: Fibonacci +============== + +Let's write a few functions in class: + +:ref:`exercise_fibonacci` + + +Lightning Talk: +--------------- + +.. rst-class:: center medium + +Shu A Latif Boolean Expressions @@ -703,11 +1015,11 @@ Truthiness What is true or false in Python? -.. rst-class:: build +* The Booleans: ``True`` and ``False`` -* The Booleans: ``True`` and ``False`` * "Something or Nothing" -* http://mail.python.org/pipermail/python-dev/2002-April/022107.html + +* http://mail.python.org/pipermail/python-dev/2002-April/022107.html .. nextslide:: @@ -719,36 +1031,37 @@ Determining Truthiness: bool(something) -.. nextslide:: What is False? +What is False? +-------------- -.. rst-class:: build +* ``None`` + +* ``False`` -* ``None`` -* ``False`` * **Nothing:** -* zero of any numeric type: ``0, 0L, 0.0, 0j``. -* any empty sequence, for example, ``"", (), []``. -* any empty mapping, for example, ``{}`` . -* instances of user-defined classes, if the class defines a ``__nonzero__()`` - or ``__len__()`` method, when that method returns the integer zero or bool - value ``False``. + - Zero of any numeric type: ``0, 0L, 0.0, 0j``. + - Any empty sequence, for example, ``"", (), []``. + - Any empty mapping, for example, ``{}`` . + - Instances of user-defined classes, if the class defines a ``__nonzero__()`` or ``__len__()`` method, when that method returns the integer zero or bool value ``False``. * http://docs.python.org/library/stdtypes.html -.. nextslide:: What is True? +What is True? +------------- .. rst-class:: center large Everything Else -.. nextslide:: Pythonic Booleans +Pythonic Booleans +----------------- Any object in Python, when passed to the ``bool()`` type object, will evaluate to ``True`` or ``False``. -When you use the ``if`` keyword, it automatically does this to the statement provided. +When you use the ``if`` keyword, it automatically does this to the expression provided. Which means that this is redundant, and not Pythonic: @@ -768,8 +1081,8 @@ Instead, use what Python gives you: do_something() -and, or and not ----------------- +``and``, ``or`` and ``not`` +--------------------------- Python has three boolean keywords, ``and``, ``or`` and ``not``. @@ -816,12 +1129,12 @@ statements: else return x if x is false, - x and y return x - else return y + x and y return x + else return y if x is false, - not x return True, - else return False + not x return True, + else return False .. nextslide:: Chaining @@ -836,12 +1149,13 @@ The first value that defines the result is returned .. ifslides:: - .. rst-class:: centered + .. rst-class:: centered large (demo) -.. nextslide:: Ternary Expressions +Ternary Expressions +------------------- This is a fairly common idiom: @@ -869,7 +1183,7 @@ PEP 308: Boolean Return Values --------------------- -Remember this puzzle from your CodingBat exercises? +Remember this puzzle from the CodingBat exercises? .. code-block:: python @@ -925,29 +1239,26 @@ And you can even do math with them (though it's a bit odd to do so): (demo) -In-Class Lab: -============= +Lightning Talk: +--------------- -.. rst-class:: center large +.. rst-class:: center medium -Better With Booleans +Spencer G McGhin -Exercises ---------- - * Look up the ``%`` operator. What do these do? +LAB: Booleans +============= + +.. rst-class:: left + + Working with Booleans, Ternary Expressions, etc: + + Re-write a couple CodingBat exercises, returning the direct boolean results, and/or using ternary expressions. - * ``10 % 7 == 3`` - * ``14 % 7 == 0`` - * Write a program that prints the numbers from 1 to 100 inclusive. But for - multiples of three print "Fizz" instead of the number and for the - multiples of five print "Buzz". For numbers which are multiples of both - three and five print "FizzBuzz" instead. - * Re-write a couple of CodingBat exercises, using a conditional expression - * Re-write a couple of CodingBat exercises, returning the direct boolean results + Experiment with ``locals`` by adding this statement one of the functions you wrote today:: -use whichever you like, or the ones in: -:download:`codingbat.rst <../code/session02/codingbat.rst>` + print(locals()) Code Structure, Modules, and Namespaces @@ -983,7 +1294,7 @@ You can put a one-liner after the colon: .. code-block:: ipython In [167]: x = 12 - In [168]: if x > 4: print x + In [168]: if x > 4: print(x) 12 But this should only be done if it makes your code **more** readable. @@ -1077,7 +1388,8 @@ inside it. (demo) -.. nextslide:: importing from packages +importing from packages +----------------------- .. code-block:: python @@ -1093,7 +1405,7 @@ inside it. http://effbot.org/zone/import-confusion.htm -.. nextslide:: importing from packages +.. nextslide:: .. code-block:: python @@ -1104,21 +1416,22 @@ http://effbot.org/zone/import-confusion.htm **Don't do this!** -Import ------- +``import`` +---------- When you import a module, or a symbol from a module, the Python code is *compiled* to **bytecode**. The result is a ``module.pyc`` file. -This process **executes all code at the module scope**. +Then after compiling, all the code in the module is run **at the module scope**. For this reason, it is good to avoid module-scope statements that have global side-effects. -.. nextslide:: Re-import +Re-import +---------- The code in a module is NOT re-run when imported again @@ -1126,8 +1439,8 @@ It must be explicitly reloaded to be re-run .. code-block:: python - import modulename - reload(modulename) + import importlib + importlib.reload(modulename) .. ifslides:: @@ -1150,7 +1463,7 @@ There are a few ways to do this: * ``In [149]: run hello.py`` -- at the IPython prompt -- running a module brings its names into the interactive namespace -.. nextslide:: Running a Module +.. nextslide Like importing, running a module executes all statements at the module level. @@ -1161,8 +1474,7 @@ is the same as the filename. When you *run* a module, the value of the symbol ``__name__`` is ``__main__``. -This allows you to create blocks of code that are executed *only when you run a -module* +This allows you to create blocks of code that are executed *only when you run a module* .. code-block:: python @@ -1174,7 +1486,7 @@ module* This is useful in a number of cases. -You can put code here that lets your module be a utility script +You can put code here that lets your module be a utility *script* You can put code here that demonstrates the functions contained in your module @@ -1185,39 +1497,11 @@ You can put code here that proves that your module works. [demo] -.. nextslide:: ``Assert`` - -Writing ``tests`` that demonstrate that your program works is an important part -of learning to program. - -The python ``assert`` statement is useful in writing ``main`` blocks that test -your code. - -.. code-block:: ipython - - In [1]: def add(n1, n2): - ...: return n1 + n2 - ...: - - In [2]: assert add(3, 4) == 7 - - In [3]: assert add(3, 4) == 10 - --------------------------------------------------------------------------- - AssertionError Traceback (most recent call last) - in () - ----> 1 assert add(3, 4) == 10 - - AssertionError: - -In-Class Lab -============ Import Interactions +------------------- -Exercises ---------- - -Experiment with importing different ways: +Let's experiment with importing different ways: .. code-block:: ipython @@ -1257,10 +1541,9 @@ Experiment with importing different ways: .. code-block:: python import sys - print sys.path + print(sys.path) import os - print os.path - + print(os.path) You wouldn't want to import * those! @@ -1271,109 +1554,48 @@ You wouldn't want to import * those! os.path.split('/foo/bar/baz.txt') os.path.join('/foo/bar', 'baz.txt') -Homework -======== - -You have two tasks to complete by next class: - -Task 1 ------- - -The Ackermann function, A(m, n), is defined:: - - A(m, n) = - n+1 if m = 0 - A(m−1, 1) if m > 0 and n = 0 - A(m−1, A(m, n−1)) if m > 0 and n > 0. - -See http://en.wikipedia.org/wiki/Ackermann_function. -Create a new module called ``ack.py`` in a ``session02`` folder in your student folder. In that module, write a function named ``ack`` that performs Ackermann's function. +Next Class +========== -* Write a good ``docstring`` for your function according to PEP 257. -* Ackermann's function is not defined for input values less than 0. Validate - inputs to your function and return None if they are negative. +.. rst-class left -.. nextslide:: - -The wikipedia page provides a table of output values for inputs between 0 and -4. Using this table, add a ``if __name__ == "__main__":`` block to test your -function. - -Test each pair of inputs between 0 and 4 and assert that the result produced by -your function is the result expected by the wikipedia table. - -When your module is run from the command line, these tests should be executed. -If they all pass, print "All Tests Pass" as the result. - -Add your new module to your git clone and commit frequently while working on -your implementation. Include good commit messages that explain concisely both -*what* you are doing and *why*. - -When you are finished, push your changes to your fork of the class repository -in GitHub. Then make a pull request and submit your assignment in Canvas. - -:: - - - Adapted from "Think Python": Chapter 6, exercise 5. - -Task 2 ------- - -The `Fibonacci Series`_ is a numeric series starting with the integers 0 and 1. -In this series, the next integer is determined by summing the previous two. -This gives us:: - - 0, 1, 1, 2, 3, 5, 8, 13, ... - -Create a new module ``series.py`` in the ``session02`` folder in your student folder. In it, add a function called ``fibonacci``. The function should have one parameter ``n``. The function should return the ``nth`` value in the fibonacci series. - -Ensure that your function has a well-formed ``docstring`` +* Sequences +* Iteration +* Strings and String Formatting -.. _Fibonacci Series: http://en.wikipedia.org/wiki/Fibbonaci_Series +* Lightning talks by: -.. nextslide:: + - Beatrice He + - Bradley I Baumel + - Jerry Bearer + - Sheree Pena -The `Lucas Numbers`_ are a related series of integers that start with the -values 2 and 1 rather than 0 and 1. The resulting series looks like this:: - 2, 1, 3, 4, 7, 11, 18, 29, ... +Office hours: Sunday 10:00 -- 12:00 -.. _Lucas Numbers: http://en.wikipedia.org/wiki/Lucas_number -In your ``series.py`` module, add a new function ``lucas`` that returns the -``nth`` value in the *lucas numbers* +Homework +--------- -Ensure that your function has a well-formed ``docstring`` +Review and/or finish reading these class notes. -.. nextslide:: +Finish any labs from class.... -Both the *fibonacci series* and the *lucas numbers* are based on an identical -formula. +**Reading:** -Add a third function called ``sum_series`` with one required parameter and two -optional parameters. The required parameter will determine which element in the -series to print. The two optional parameters will have default values of 0 and -1 and will determine the first two values for the series to be produced. +Think Python, chapters 8, 9, 10, 12 -Calling this function with no optional parameters will produce numbers from the -*fibonacci series*. Calling it with the optional arguments 2 and 1 will -produce values from the *lucas numbers*. Other values for the optional -parameters will produce other series. +(http://greenteapress.com/thinkpython/html/thinkpython009.html) -Ensure that your function has a well-formed ``docstring`` +Learn Python the Hard way: exercises 11 -- 14, 18, 19, 21, 28-33 +(the ones in between are about files -- we'll get to that later.) -.. nextslide:: +http://learnpythonthehardway.org/book/ex11.html -Add an ``if __name__ == "__main__":`` block to the end of your ``series.py`` -module. Use the block to write a series of ``assert`` statements that -demonstrate that your three functions work properly. +NOTE: In python3, you use ``input``, rather than ``raw_input`` -Use comments in this block to inform the observer what your tests do. +Dive Into Python: chapter 4 -Add your new module to your git clone and commit frequently while working on -your implementation. Include good commit messages that explain concisely both -*what* you are doing and *why*. +(http://www.diveintopython3.net/strings.html) -When you are finished, push your changes to your fork of the class repository -in GitHub. Then make a pull request and submit your assignment in Canvas. diff --git a/slides_sources/source/session03.rst b/_sources/session03.txt similarity index 59% rename from slides_sources/source/session03.rst rename to _sources/session03.txt index 3bed59d1..bd58f2ff 100644 --- a/slides_sources/source/session03.rst +++ b/_sources/session03.txt @@ -1,3 +1,5 @@ +.. include:: include.rst + ********************************************************* Session Three: Sequences, Iteration and String Formatting ********************************************************* @@ -8,20 +10,47 @@ Review/Questions Review of Previous Session -------------------------- -.. rst-class:: build - * Functions + + - recursion + - optional arguments + * Booleans + + - if and conditional expressions + * Modules Homework Review --------------- +* FizzBuzz + +* Series + .. rst-class:: center large Any questions that are nagging? +git +--- + +.. rst-class:: center large + + OK -- we'll answer git questions... + +Lightning Talks Today: +---------------------- + +.. rst-class:: mlarge + +| +| Beatrice He +| Bradley I Baumel +| Jerry Bearer +| Sheree Pena + Sequences ========= @@ -34,7 +63,9 @@ Ordered collections of objects What is a Sequence? ------------------- -Remember Duck Typing? A *sequence* can be considered as anything that supports +Remember Duck Typing? + +A *sequence* can be considered as anything that supports *at least* these operations: .. rst-class:: build @@ -50,37 +81,38 @@ Remember Duck Typing? A *sequence* can be considered as anything that supports Sequence Types -------------- -There are seven builtin types in Python that are *sequences*: +There are eight builtin types in Python that are *sequences*: -* strings -* Unicode strings -* lists -* tuples -* bytearrays -* buffers -* array.arrays -* xrange objects (almost) +* string +* list +* tuple +* bytes +* bytearray +* buffer +* array.array +* range object (almost) -For this class, you won't see much beyond the string types, lists, tuples -- the rest are pretty special purpose. +For this class, you won't see much beyond string, lists, and tuples -- +the rest are pretty special purpose. -But what we say today applies to all sequences (with minor caveats) +But what we learn today applies to all sequences (with minor caveats) Indexing -------- -Items in a sequence may be looked up by *index* using the subscription +Items in a sequence may be looked up by *index* using the indexing operator: ``[]`` Indexing in Python always starts at zero. .. code-block:: ipython - In [98]: s = u"this is a string" + In [98]: s = "this is a string" In [99]: s[0] - Out[99]: u't' + Out[99]: 't' In [100]: s[5] - Out[100]: u'i' + Out[100]: 'i' .. nextslide:: @@ -89,11 +121,16 @@ You can use negative indexes to count from the end: .. code-block:: ipython - In [105]: s = u"this is a string" - In [106]: s[-1] - Out[106]: u'g' - In [107]: s[-6] - Out[107]: u's' + In [2]: a_list = [34, 56, 19, 23, 55] + + In [3]: a_list[-1] + Out[3]: 55 + + In [4]: a_list[-2] + Out[4]: 23 + + In [5]: a_list[-4] + Out[5]: 56 .. nextslide:: @@ -101,45 +138,46 @@ Indexing beyond the end of a sequence causes an IndexError: .. code-block:: ipython - In [4]: s = [0, 1, 2, 3] - In [5]: s[4] + In [6]: a_list + Out[6]: [34, 56, 19, 23, 55] + + In [7]: a_list[5] --------------------------------------------------------------------------- IndexError Traceback (most recent call last) - in () - ----> 1 s[4] + in () + ----> 1 a_list[5] IndexError: list index out of range - Slicing ------- Slicing a sequence creates a new sequence with a range of objects from the original sequence. -It also uses the subscription operator (``[]``), but with a twist. +It also uses the indexing operator (``[]``), but with a twist. ``sequence[start:finish]`` returns all sequence[i] for which start <= i < finish: .. code-block:: ipython - In [121]: s = u"a bunch of words" + In [121]: s = "a bunch of words" In [122]: s[2] - Out[122]: u'b' + Out[122]: 'b' In [123]: s[6] - Out[123]: u'h' + Out[123]: 'h' In [124]: s[2:6] - Out[124]: u'bunc' + Out[124]: 'bunc' In [125]: s[2:7] - Out[125]: u'bunch' + Out[125]: 'bunch' .. nextslide:: Helpful Hint Think of the indexes as pointing to the spaces between the items:: - a b u n c h o f - | | | | | | | | | | - 0 1 2 3 4 5 6 7 8 9 + a b u n c h o f w o r d s + | | | | | | | | | | | | | | | | + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @@ -149,11 +187,11 @@ You do not have to provide both ``start`` and ``finish``: .. code-block:: ipython - In [6]: s = u"a bunch of words" + In [6]: s = "a bunch of words" In [7]: s[:5] - Out[7]: u'a bun' + Out[7]: 'a bun' In [8]: s[5:] - Out[8]: u'ch of words' + Out[8]: 'ch of words' Either ``0`` or ``len(s)`` will be assumed, respectively. @@ -161,11 +199,11 @@ You can combine this with the negative index to get the end of a sequence: .. code-block:: ipython - In [4]: s = u'this_could_be_a_filename.txt' + In [4]: s = 'this_could_be_a_filename.txt' In [5]: s[:-4] - Out[5]: u'this_could_be_a_filename' + Out[5]: 'this_could_be_a_filename' In [6]: s[-4:] - Out[6]: u'.txt' + Out[6]: '.txt' Why start from zero? @@ -173,11 +211,11 @@ Why start from zero? Python indexing feels 'weird' to some folks -- particularly those that don't come with a background in the C family of languages. -Why is the "first" item indexed with zero? +Why is the "first" item indexed with **zero**? Why is the last item in the slice **not** included? -Because these lead to some nifty properties:: +*Because* these lead to some nifty properties:: len(seq[a:b]) == b-a @@ -197,16 +235,20 @@ returned: .. code-block:: ipython - In [289]: string = u"a fairly long string" - In [290]: string[0:15] - Out[290]: u'a fairly long s' - In [291]: string[0:15:2] - Out[291]: u'afil ogs' - In [292]: string[0:15:3] - Out[292]: u'aallg' - In [293]: string[::-1] - Out[293]: u'gnirts gnol ylriaf a' + In [18]: a_tuple + Out[18]: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) + + In [19]: a_tuple[0:15] + Out[19]: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + + In [20]: a_tuple[0:15:2] + Out[20]: (0, 2, 4, 6, 8, 10, 12, 14) + In [21]: a_tuple[0:15:3] + Out[21]: (0, 3, 6, 9, 12) + + In [22]: a_tuple[::-1] + Out[22]: (19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) .. nextslide:: Slicing vs. Indexing @@ -228,7 +270,7 @@ Indexing past the end of a sequence will raise an error, slicing will not: In [131]: s[10:20] Out[131]: ' words' In [132]: s[20:30] - Out[132]: " + Out[132]: '' (demo) @@ -255,8 +297,8 @@ other languages: .. code-block:: ipython - In [20]: s = u"This is a long string" - In [21]: u"long" in s + In [20]: s = "This is a long string" + In [21]: "long" in s Out[21]: True This does not work for sub-sequences of other types (can you think of why?): @@ -275,13 +317,12 @@ Using ``+`` or ``*`` on sequences will *concatenate* them: .. code-block:: ipython - In [25]: s1 = u"left" - In [26]: s2 = u"right" - In [27]: s1 + s2 - Out[27]: u'leftright' - In [28]: (s1 + s2) * 3 - Out[28]: u'leftrightleftrightleftright' - + In [18]: l1 = [1,2,3,4] + In [19]: l2 = [5,6,7,8] + In [20]: l1 + l2 + Out[20]: [1, 2, 3, 4, 5, 6, 7, 8] + In [21]: (l1+l2) * 2 + Out[21]: [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8] .. nextslide:: Multiplying and Slicing @@ -312,12 +353,11 @@ All sequences have a length. You can get it with the ``len`` builtin: .. code-block:: ipython - In [36]: s = u"how long is this, anyway?" + In [36]: s = "how long is this, anyway?" In [37]: len(s) Out[37]: 25 -Remember, Python sequences are zero-indexed, so the last index in a sequence is -``len(s) - 1``: +Remember: Sequences are 0-indexed, so the last index is ``len(s)-1``: .. code-block:: ipython @@ -343,34 +383,34 @@ All sequences also support the ``min`` and ``max`` builtins: .. code-block:: ipython - In [42]: all_letters = u"thequickbrownfoxjumpedoverthelazydog" + In [42]: all_letters = "thequickbrownfoxjumpedoverthelazydog" In [43]: min(all_letters) - Out[43]: u'a' + Out[43]: 'a' In [44]: max(all_letters) - Out[44]: u'z' + Out[44]: 'z' -Why are those the answers you get? (hint: ``ord(u'a')``) +Why are those the answers you get? (hint: ``ord('a')``) +Of course this works with numbers, too! .. nextslide:: Index -All sequences also support the ``index`` method, which returns the index of the -first occurence of an item in the sequence: +All sequences also support the ``index`` method, which returns the index of the first occurence of an item in the sequence: .. code-block:: ipython - In [46]: all_letters.index(u'd') + In [46]: all_letters.index('d') Out[46]: 21 This causes a ``ValueError`` if the item is not in the sequence: .. code-block:: ipython - In [47]: all_letters.index(u'A') + In [47]: all_letters.index('A') --------------------------------------------------------------------------- ValueError Traceback (most recent call last) in () - ----> 1 all_letters.index(u'A') + ----> 1 all_letters.index('A') ValueError: substring not found @@ -381,25 +421,47 @@ appears: .. code-block:: ipython - In [52]: all_letters.count(u'o') + In [52]: all_letters.count('o') Out[52]: 4 - In [53]: all_letters.count(u'the') + In [53]: all_letters.count('the') Out[53]: 2 This does not raise an error if the item you seek is not present: .. code-block:: ipython - In [54]: all_letters.count(u'A') + In [54]: all_letters.count('A') Out[54]: 0 Iteration --------- -.. rst-class:: center large +.. rst-class:: center mlarge + + All sequences are "iterables" -- + + More on this in a while. + +Slicing LAB +=========== + +.. rst-class:: center medium + + Let's practice Slicing! + + :ref:`exercise_slicing` + + +Lightning Talks +---------------- -More on this in a while. +| +| Beatrice He +| +| +| Bradley Baumel +| Lists, Tuples... @@ -407,7 +469,7 @@ Lists, Tuples... .. rst-class:: center large -The *other* sequence types. +The *primary* sequence types. Lists ----- @@ -434,6 +496,7 @@ Or by using the ``list`` type object as a constructor: In [8]: list('abc') Out[8]: ['a', 'b', 'c'] +It will take any "iterable" .. nextslide:: List Elements @@ -446,13 +509,13 @@ multiple names (or no name) .. code-block:: ipython - In [9]: name = u'Brian' + In [9]: name = 'Brian' In [10]: a = [1, 2, name] In [11]: b = [3, 4, name] In [12]: a[2] - Out[12]: u'Brian' + Out[12]: 'Brian' In [13]: b[2] - Out[13]: u'Brian' + Out[13]: 'Brian' In [14]: a[2] is b[2] Out[14]: True @@ -497,14 +560,13 @@ But they *do* need commas...! In [156]: t = ( 3 ) In [157]: type(t) Out[157]: int - In [158]: t = (3,) + In [158]: t = ( 3, ) In [160]: type(t) Out[160]: tuple .. nextslide:: Converting to Tuple -You can also use the ``tuple`` type object to convert any sequence into a -tuple: +You can also use the ``tuple`` type object to convert any iterable(sequence) into a tuple: .. code-block:: ipython @@ -527,12 +589,12 @@ multiple names (or no name) .. code-block:: ipython - In [23]: name = u'Brian' + In [23]: name = 'Brian' In [24]: other = name In [25]: a = (1, 2, name) In [26]: b = (3, 4, other) In [27]: for i in range(3): - ....: print a[i] is b[i], + ....: print(a[i] is b[i], end=' ') ....: False False True @@ -540,7 +602,7 @@ multiple names (or no name) .. rst-class:: center large -So Why Have Both? + So Why Have Both? Mutability @@ -569,18 +631,18 @@ Objects which are mutable may be *changed in place*. Objects which are immutable may not be changed. +Ever. .. nextslide:: The Types We Know -========= ======= +========= =========== Immutable Mutable -========= ======= -Unicode List -String -Integer +========= =========== +String List +Integer Dictionary Float Tuple -========= ======= +========= =========== .. nextslide:: Lists Are Mutable @@ -589,12 +651,12 @@ Try this out: .. code-block:: ipython - In [28]: food = [u'spam', u'eggs', u'ham'] + In [28]: food = ['spam', 'eggs', 'ham'] In [29]: food - Out[29]: [u'spam', u'eggs', u'ham'] - In [30]: food[1] = u'raspberries' + Out[29]: ['spam', 'eggs', 'ham'] + In [30]: food[1] = 'raspberries' In [31]: food - Out[31]: [u'spam', u'raspberries', u'ham'] + Out[31]: ['spam', 'raspberries', 'ham'] .. nextslide:: Tuples Are Not @@ -603,14 +665,14 @@ And repeat the exercise with a Tuple: .. code-block:: ipython - In [32]: food = (u'spam', u'eggs', u'ham') + In [32]: food = ('spam', 'eggs', 'ham') In [33]: food - Out[33]: (u'spam', u'eggs', u'ham') - In [34]: food[1] = u'raspberries' + Out[33]: ('spam', 'eggs', 'ham') + In [34]: food[1] = 'raspberries' --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () - ----> 1 food[1] = u'raspberries' + ----> 1 food[1] = 'raspberries' TypeError: 'tuple' object does not support item assignment @@ -665,7 +727,7 @@ Easy container setup, or deadly trap? In [14]: bins Out[14]: [[], [], [], [], []] - In [15]: words = [u'one', u'three', u'rough', u'sad', u'goof'] + In [15]: words = ['one', 'three', 'rough', 'sad', 'goof'] In [16]: for word in words: ....: bins[len(word)-1].append(word) @@ -679,15 +741,15 @@ So, what is going to be in ``bins`` now? In [65]: bins Out[65]: - [[u'one', u'three', u'rough', u'sad', u'goof'], - [u'one', u'three', u'rough', u'sad', u'goof'], - [u'one', u'three', u'rough', u'sad', u'goof'], - [u'one', u'three', u'rough', u'sad', u'goof'], - [u'one', u'three', u'rough', u'sad', u'goof']] + [['one', 'three', 'rough', 'sad', 'goof'], + ['one', 'three', 'rough', 'sad', 'goof'], + ['one', 'three', 'rough', 'sad', 'goof'], + ['one', 'three', 'rough', 'sad', 'goof'], + ['one', 'three', 'rough', 'sad', 'goof']] We multiplied a sequence containing a single *mutable* object. -We got a list containing five pointers to a single *mutable* object. +We got a list containing five references to a single *mutable* object. .. nextslide:: Mutable Default Argument @@ -717,7 +779,7 @@ used to change the list. You can find all these in the Standard Library Documentation: -http://www.python.org/2/library/stdtypes.html#mutable-sequence-types +https://docs.python.org/3/library/stdtypes.html#typesseq-mutable Assignment ----------- @@ -741,16 +803,16 @@ Growing the List .. code-block:: ipython - In [74]: food = [u'spam', u'eggs', u'ham'] - In [75]: food.append(u'sushi') + In [74]: food = ['spam', 'eggs', 'ham'] + In [75]: food.append('sushi') In [76]: food - Out[76]: [u'spam', u'eggs', u'ham', u'sushi'] - In [77]: food.insert(0, u'beans') + Out[76]: ['spam', 'eggs', 'ham', 'sushi'] + In [77]: food.insert(0, 'beans') In [78]: food - Out[78]: [u'beans', u'spam', u'eggs', u'ham', u'sushi'] - In [79]: food.extend([u'bread', u'water']) + Out[78]: ['beans', 'spam', 'eggs', 'ham', 'sushi'] + In [79]: food.extend(['bread', 'water']) In [80]: food - Out[80]: [u'beans', u'spam', u'eggs', u'ham', u'sushi', u'bread', u'water'] + Out[80]: ['beans', 'spam', 'eggs', 'ham', 'sushi', 'bread', 'water'] .. nextslide:: More on Extend @@ -760,12 +822,12 @@ You can pass any sequence to ``.extend()``: .. code-block:: ipython In [85]: food - Out[85]: [u'beans', u'spam', u'eggs', u'ham', u'sushi', u'bread', u'water'] - In [86]: food.extend(u'spaghetti') + Out[85]: ['beans', 'spam', 'eggs', 'ham', 'sushi', 'bread', 'water'] + In [86]: food.extend('spaghetti') In [87]: food Out[87]: - [u'beans', u'spam', u'eggs', u'ham', u'sushi', u'bread', u'water', - u's', u'p', u'a', u'g', u'h', u'e', u't', u't', u'i'] + ['beans', 'spam', 'eggs', 'ham', 'sushi', 'bread', 'water', + 's', 'p', 'a', 'g', 'h', 'e', 't', 't', 'i'] Shrinking the List @@ -863,9 +925,7 @@ Consider this common pattern: if should_be_removed(x): somelist.remove(x) -This looks benign enough, but changing a list while you are iterating over it -can be the cause of some pernicious bugs. - +This looks benign enough, but changing a list while you are iterating over it can be the cause of some pernicious bugs. .. nextslide:: The Problem @@ -873,14 +933,14 @@ For example: .. code-block:: ipython - In [121]: list = range(10) - In [122]: list - Out[122]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - In [123]: for x in list: - .....: list.remove(x) - .....: - In [124]: list - Out[124]: [1, 3, 5, 7, 9] + In [27]: l = list(range(10)) + In [28]: l + Out[28]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + In [29]: for item in l: + ....: l.remove(item) + ....: + In [30]: l + Out[30]: [1, 3, 5, 7, 9] Was that what you expected? @@ -890,12 +950,13 @@ Iterate over a copy, and mutate the original: .. code-block:: ipython - In [126]: list = range(10) - In [127]: for x in list[:]: - .....: list.remove(x) - .....: - In [128]: list - Out[128]: [] + In [33]: l = list(range(10)) + + In [34]: for item in l[:]: + ....: l.remove(item) + ....: + In [35]: l + Out[35]: [] .. nextslide:: Just Say It, Already @@ -909,26 +970,25 @@ You can iterate over a sequence. for element in sequence: do_something(element) +which is what we mean when we say a sequence is an "iterable". -Again, we'll touch more on this in a short while, but first a few more words -about Lists and Tuples. +Again, we'll touch more on this in a short while, but first a few more words about Lists and Tuples. Miscellaneous List Methods -------------------------- -These methods change a list in place and are not available on immutable -sequence types. +These methods change a list in place and are not available on immutable sequence types. ``.reverse()`` .. code-block:: ipython - In [129]: food = [u'spam', u'eggs', u'ham'] + In [129]: food = ['spam', 'eggs', 'ham'] In [130]: food.reverse() In [131]: food - Out[131]: [u'ham', u'eggs', u'spam'] + Out[131]: ['ham', 'eggs', 'spam'] ``.sort()`` @@ -936,18 +996,16 @@ sequence types. In [132]: food.sort() In [133]: food - Out[133]: [u'eggs', u'ham', u'spam'] + Out[133]: ['eggs', 'ham', 'spam'] -Because these methods mutate the list in place, they have a return value of -``None`` +Because these methods mutate the list in place, they have a return value of ``None`` .. nextslide:: Custom Sorting ``.sort()`` can take an optional ``key`` parameter. -It should be a function that takes one parameter (list items one at a time) and -returns something that can be used for sorting: +It should be a function that takes one parameter (list items one at a time) and returns something that can be used for sorting: .. code-block:: ipython @@ -956,7 +1014,7 @@ returns something that can be used for sorting: .....: In [138]: food.sort(key=third_letter) In [139]: food - Out[139]: [u'spam', u'eggs', u'ham'] + Out[139]: ['spam', 'eggs', 'ham'] @@ -966,16 +1024,16 @@ List Performance .. rst-class:: build * indexing is fast and constant time: O(1) -* x in s proportional to n: O(n) +* ``x in l`` is proportional to n: O(n) * visiting all is proportional to n: O(n) -* operating on the end of list is fast and constant time: O(1) +* operating on the end of list is fast and constant time: O(1) * append(), pop() * operating on the front (or middle) of the list depends on n: O(n) - * pop(0), insert(0, v) - * But, reversing is fast. Also, collections.deque + * ``pop(0)``, ``insert(0, v)`` + * But, reversing is fast. ``Also, collections.deque`` http://wiki.python.org/moin/TimeComplexity @@ -994,10 +1052,12 @@ Here are a few guidelines on when to choose a list or a tuple: Otherwise ... taste and convention -.. nextslide:: Convention +Convention +----------- + Lists are Collections (homogeneous): --- contain values of the same type +-- contain values of the same type -- simplifies iterating, sorting, etc tuples are mixed types: @@ -1005,7 +1065,8 @@ tuples are mixed types: -- Kind of like simple C structs. -.. nextslide:: Other Considerations +Other Considerations +-------------------- .. rst-class:: build @@ -1035,10 +1096,51 @@ More Documentation For more information, read the list docs: -http://docs.python.org/2/library/stdtypes.html#mutable-sequence-types +https://docs.python.org/3.5/library/stdtypes.html#mutable-sequence-types (actually any mutable sequence....) +One Last Trick +--------------- + +.. rst-class:: left + +For some of the exercises, you'll need to interact with a user at the +command line. + +There's a nice built in function to do this - ``input``: + +.. code-block:: ipython + + In [85]: fred = input('type something-->') + type something-->I've typed something + + In [86]: print(fred) + I've typed something + +This will display a prompt to the user, allowing them to input text and +allowing you to bind that input to a symbol. + +LAB +==== + +List Lab +--------- + +Let's play a bit with Python lists... + +:ref:`exercise_list_lab` + + + +Lightning Talks +--------------- + +| +| Jerry Bearer +| +| Sheree Pena +| Iteration ========= @@ -1056,7 +1158,7 @@ We've seen simple iteration over a sequence with ``for ... in``: .. code-block:: ipython In [170]: for x in "a string": - .....: print x + .....: print(x) .....: a s @@ -1073,28 +1175,29 @@ Contrast this with other languages, where you must build and use an ``index``: .. code-block:: javascript - for(var i=0; i 50: .....: break .....: @@ -1151,11 +1269,11 @@ allow iteration to continue: .....: break .....: if i < 25: .....: continue - .....: print i, + .....: print(i, end=' ') .....: 25 26 27 28 29 ... 41 42 43 44 45 46 47 48 49 50 -.. nextslide:: Else +.. nextslide:: else For loops can also take an optional ``else`` block. @@ -1167,14 +1285,14 @@ Executed only when the loop exits normally (not via break): .....: if x == 11: .....: break .....: else: - .....: print 'finished' + .....: print('finished') finished In [148]: for x in range(10): .....: if x == 5: - .....: print x + .....: print(x) .....: break .....: else: - .....: print 'finished' + .....: print('finished') 5 This is a really nice unique Python feature! @@ -1194,9 +1312,7 @@ It continues to execute the body until condition is not ``True``:: ``while`` is more general than ``for`` --- you can always express ``for`` as ``while``, - -but not always vice-versa. +-- you can always express ``for`` as ``while``, but not always vice-versa. ``while`` is more error-prone -- requires some care to terminate @@ -1208,7 +1324,7 @@ potential error -- infinite loops: i = 0; while i < 5: - print i + print(i) .. nextslide:: Terminating a while Loop @@ -1221,7 +1337,7 @@ Use ``break``: .....: i += 1 .....: if i > 10: .....: break - .....: print i + .....: print(i) .....: 1 2 3 4 5 6 7 8 9 10 @@ -1235,7 +1351,7 @@ Set a flag: In [157]: keep_going = True In [158]: while keep_going: .....: num = random.choice(range(5)) - .....: print num + .....: print(num) .....: if num == 3: .....: keep_going = False .....: @@ -1249,7 +1365,7 @@ Use a condition: In [161]: while i < 10: .....: i += random.choice(range(4)) - .....: print i + .....: print(i) .....: 0 0 2 3 4 6 8 8 8 9 12 @@ -1267,15 +1383,46 @@ loop terminates normally (no ``break``) String Features -================= +================ .. rst-class:: center large Fun with Strings +Strings +--------- -Manipulations -------------- +A string literal creates a string type + +(we've seen this already...) + +:: + + "this is a string" + + 'So is this' + + """and this also""" + +You can also use ``str()`` + +.. code-block:: ipython + + In [256]: str(34) + Out[256]: '34' + +(demo) + + +String Methods +=============== + +String objects have a lot of methods. + +Here are just a few: + +String Manipulations +--------------------- ``split`` and ``join``: @@ -1289,353 +1436,292 @@ Manipulations Out[170]: 'comma|separated|values' -.. nextslide:: Case Switching +Case Switching +-------------- .. code-block:: ipython - In [171]: sample = u'A long string of words' + In [171]: sample = 'A long string of words' In [172]: sample.upper() - Out[172]: u'A LONG STRING OF WORDS' + Out[172]: 'A LONG STRING OF WORDS' In [173]: sample.lower() - Out[173]: u'a long string of words' + Out[173]: 'a long string of words' In [174]: sample.swapcase() - Out[174]: u'a LONG STRING OF WORDS' + Out[174]: 'a LONG STRING OF WORDS' In [175]: sample.title() - Out[175]: u'A Long String Of Words' + Out[175]: 'A Long String Of Words' -.. nextslide:: Testing +Testing +-------- .. code-block:: ipython - In [181]: number = u"12345" + In [181]: number = "12345" In [182]: number.isnumeric() Out[182]: True In [183]: number.isalnum() Out[183]: True In [184]: number.isalpha() Out[184]: False - In [185]: fancy = u"Th!$ $tr!ng h@$ $ymb0l$" + In [185]: fancy = "Th!$ $tr!ng h@$ $ymb0l$" In [186]: fancy.isalnum() Out[186]: False -Ordinal values --------------- +String Literals +----------------- -"ASCII" values: 1-127 +Common Escape Sequences:: -"ANSI" values: 1-255 + \\ Backslash (\) + \a ASCII Bell (BEL) + \b ASCII Backspace (BS) + \n ASCII Linefeed (LF) + \r ASCII Carriage Return (CR) + \t ASCII Horizontal Tab (TAB) + \ooo Character with octal value ooo + \xhh Character with hex value hh -To get the value: +for example -- for tab-separated values: .. code-block:: ipython - In [109]: for i in 'Chris': - .....: print ord(i), - 67 104 114 105 115 - In [110]: for i in (67,104,114,105,115): - .....: print chr(i), - C h r i s - - -Building Strings ----------------- - -You can, but please don't do this: + In [25]: s = "these\tare\tseparated\tby\ttabs" -.. code-block:: python + In [26]: print(s) + these are separated by tabs - 'Hello ' + name + '!' +https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals +https://docs.python.org/3/library/stdtypes.html#string-methods -Do this instead: +Raw Strings +------------ -.. code-block:: python +Add an ``r`` in front of the string literal: - 'Hello %s!' % name +Escape Sequences Ignored -It's much faster and safer, and easier to modify as code gets complicated. +.. code-block:: ipython -http://docs.python.org/library/stdtypes.html#string-formatting-operations + In [408]: print("this\nthat") + this + that + In [409]: print(r"this\nthat") + this\nthat +**Gotcha** -.. nextslide:: String Formatting +.. code-block:: ipython -The string format operator: ``%`` + In [415]: r"\" + SyntaxError: EOL while scanning string literal -.. code-block:: ipython +(handy for regex, windows paths...) - In [261]: u"an integer is: %i" % 34 - Out[261]: u'an integer is: 34' - In [262]: u"a floating point is: %f" % 34.5 - Out[262]: u'a floating point is: 34.500000' - In [263]: u"a string is: %s" % u"anything" - Out[263]: u'a string is: anything' -.. nextslide:: More Placeholders +Ordinal values +-------------- -Multiple placeholders: +Characters in strings are stored as numeric values: -.. code-block:: ipython +* "ASCII" values: 1-127 - In [264]: u"the number %s is %i" % (u'five', 5) - Out[264]: u'the number five is 5' - In [266]: u"the first 3 numbers are: %i, %i, %i" % (1,2,3) - Out[266]: u'the first 3 numbers are: 1, 2, 3' +* Unicode values -- 1 - 1,114,111 (!!!) -The counts must agree: +To get the value: .. code-block:: ipython - In [187]: u"string with %i formatting %s" % (1, ) - --------------------------------------------------------------------------- - ... - TypeError: not enough arguments for format string + In [109]: for i in 'Chris': + .....: print(ord(i), end=' ') + 67 104 114 105 115 + In [110]: for i in (67,104,114,105,115): + .....: print(chr(i), end='') + Chris +(these days, stick with ASCII, or use full Unicode: more on that in a few weeks) -.. nextslide:: -Named placeholders: +Building Strings +----------------- -.. code-block:: ipython +You can, but please don't do this: - In [191]: u"Hello, %(name)s, whaddaya know?" % {u'name': "Joe"} - Out[191]: u'Hello, Joe, whaddaya know?' +.. code-block:: python -You can use values more than once, and skip values: + 'Hello ' + name + '!' -.. code-block:: ipython +(I know -- we did that in the grid_printing excercise) - In [193]: u"Hi, %(name)s. Howzit, %(name)s?" % {u'name': u"Bob", u'age': 27} - Out[193]: u'Hi, Bob. Howzit, Bob?' +Do this instead: +.. code-block:: python -.. nextslide:: New Formatting + 'Hello {}!'.format(name) -In more recent versions of Python (2.6+) this is `being phased out`_ in favor of the ``.format()`` method on strings. +It's much faster and safer, and easier to modify as code gets complicated. -.. code-block:: ipython +https://docs.python.org/3/library/string.html#string-formatting - In [194]: u"Hello, {}, how's your {}".format(u"Bob", u"wife") - Out[194]: u"Hello, Bob, how's your wife" - In [195]: u"Hi, {name}. How's your {relation}?".format(name=u'Bob', relation=u'wife') - Out[195]: u"Hi, Bob. How's your wife?" +Old and New string formatting +----------------------------- +back in early python days, there was the string formatting operator: ``%`` -.. nextslide:: Complex Formatting +.. code-block:: python -For both of these forms of string formatting, there is a complete syntax for -specifying all sorts of options. + " a string: %s and a number: %i "%("text", 45) -It's well worth your while to spend some time getting to know this -`formatting language`_. You can accomplish a great deal just with this. +This is very similar to C-style string formatting (`sprintf`). -.. _formatting language: https://docs.python.org/2/library/string.html#format-specification-mini-language +It's still around, and handy --- but ... -.. _being phased out: https://docs.python.org/2/library/stdtypes.html#str.format +The "new" ``format()`` method is more powerful and flexible, so we'll focus on that in this class. +.. nextslide:: String Formatting -One Last Trick -============== +The string ``format()`` method: -.. rst-class:: left +.. code-block:: ipython -For some of your homework, you'll need to interact with a user at the -command line. + In [62]: "A decimal integer is: {:d}".format(34) + Out[62]: 'A decimal integer is: 34' -.. rst-class:: left + In [63]: "a floating point is: {:f}".format(34.5) + Out[63]: 'a floating point is: 34.500000' -There's a nice builtin function to do this - ``raw_input``: + In [64]: "a string is the default: {}".format("anything") + Out[64]: 'a string is the default: anything' -.. rst-class:: left -.. code-block:: python +Multiple placeholders: +----------------------- - In [196]: fred = raw_input('type something-->') - type something-->;alksdjf - In [197]: fred - Out[197]: ';alksdjf' +.. code-block:: ipython -.. rst-class:: left + In [65]: "the number is {} is {}".format('five', 5) + Out[65]: 'the number is five is 5' -This will display a prompt to the user, allowing them to input text and -allowing you to bind that input to a symbol. + In [66]: "the first 3 numbers are {}, {}, {}".format(1,2,3) + Out[66]: 'the first 3 numbers are 1, 2, 3' +The counts must agree: -Homework -======== +.. code-block:: ipython -Task 1 ------- + In [67]: "string with {} formatting {}".format(1) + --------------------------------------------------------------------------- + IndexError Traceback (most recent call last) + in () + ----> 1 "string with {} formatting {}".format(1) -List Lab (after http://www.upriss.org.uk/python/session5.html) + IndexError: tuple index out of range -In your student folder, create a new file called ``list_lab.py``. -The file should be an executable python script. That is to say that one -should be able to run the script directly like so: +Named placeholders: +------------------- -.. code-block:: bash +.. code-block:: ipython - $ ./list_lab.py -Add the file to your clone of the repository and commit changes frequently -while working on the following tasks. When you are done, push your changes to -GitHub and issue a pull request. + In [69]: "Hello, {name}, whaddaya know?".format(name="Joe") + Out[69]: 'Hello, Joe, whaddaya know?' -When the script is run, it should accomplish the following four series of -actions: +You can use values more than once, and skip values: -.. nextslide:: Series 1 +.. code-block:: ipython -- Create a list that contains "Apples", "Pears", "Oranges" and "Peaches". -- Display the list. -- Ask the user for another fruit and add it to the end of the list. -- Display the list. -- Ask the user for a number and display the number back to the user and the - fruit corresponding to that number (on a 1-is-first basis). -- Add another fruit to the beginning of the list using "+" and display the - list. -- Add another fruit to the beginning of the list using insert() and display the - list. -- Display all the fruits that begin with "P", using a for loop. + In [73]: "Hi, {name}. Howzit, {name}?".format(name='Bob') + Out[73]: 'Hi, Bob. Howzit, Bob?' +.. nextslide:: -.. nextslide:: Series 2 +The format operator works with string variables, too: -Using the list created in series 1 above: +.. code-block:: ipython -- Display the list. -- Remove the last fruit from the list. -- Display the list. -- Ask the user for a fruit to delete and find it and delete it. -- (Bonus: Multiply the list times two. Keep asking until a match is found. Once - found, delete all occurrences.) + In [80]: s = "{:d} / {:d} = {:f}" -.. nextslide:: Series 3 + In [81]: a, b = 12, 3 -Again, using the list from series 1: + In [82]: s.format(a, b, a/b) + Out[82]: '12 / 3 = 4.000000' -- Ask the user for input displaying a line like "Do you like apples?" -- for each fruit in the list (making the fruit all lowercase). -- For each "no", delete that fruit from the list. -- For any answer that is not "yes" or "no", prompt the user to answer with one - of those two values (a while loop is good here): -- Display the list. +So you can dynamically build a format string -.. nextslide:: Series 4 +Complex Formatting +------------------ -Once more, using the list from series 1: +There is a complete syntax for specifying all sorts of options. -- Make a copy of the list and reverse the letters in each fruit in the copy. -- Delete the last item of the original list. Display the original list and the - copy. +It's well worth your while to spend some time getting to know this +`formatting language`_. You can accomplish a great deal just with this. +.. _formatting language: https://docs.python.org/3/library/string.html#format-specification-mini-language -Task 2 ------- -ROT13 +String Formatting LAB +===================== -The ROT13 encryption scheme is a simple substitution cypher where each letter -in a text is replace by the letter 13 away from it (imagine the alphabet as a -circle, so it wraps around). +Let's play with these a bit: -Add a python module named ``rot13.py`` to your student folder. This module -should provide at least one function called ``rot13`` that takes any amount of -text and returns that same text encrypted by ROT13. +:ref:`exercise_string_formatting` -This function should preserve whitespace, punctuation and capitalization. +Homework +======== -Your module should include an ``if __name__ == '__main__':`` block with tests -that demonstrate that your ``rot13`` function and any helper functions you add -work properly. +Task 1 +------ -.. nextslide:: A bit more +Finish the List Lab from class -There is a "short-cut" available that will help you accomplish this task. Some -spelunking in `the documentation for strings`_ should help you to find it. If -you do find it, using it is completely fair game. +Finish the string formatting lab -.. _the documentation for strings: https://docs.python.org/2/library/stdtypes.html#string-methods +Task 2 +------ -As usual, add your new file to your local clone right away. Make commits early and often and include commit messages that are descriptive and concise. +.. rst-class:: mlarge -When you are done, push your changes to github and issue a pull request. +ROT13 +:ref:`exercise_rot13` Task 3 ------ -"Mail Room" - -You work in the mail room at a local charity. Part of your job is to write -incredibly boring, repetitive emails thanking your donors for their generous -gifts. You are tired of doing this over an over again, so you've decided to let Python help you out of a jam. +.. rst-class:: mlarge -Write a small command-line script called ``mailroom.py``. As with Task 1, This script should be executable. The script should accomplish the following goals: +Mail Room -* It should have a data structure that holds a list of your donors and a - history of the amounts they have donated. This structure should be populated - at first with at least five donors, with between 1 and 3 donations each -* The script should prompt the user (you) to choose from a menu of 2 actions: - 'Send a Thank You' or 'Create a Report'. +:ref:`exercise_mailroom` -.. nextslide:: Sending a Thank You - -* If the user (you) selects 'Send a Thank You', prompt for a Full Name. +Reading +------- - * If the user types 'list', show them a list of the donor names and re-prompt - * If the user types a name not in the list, add that name to the data - structure and use it. - * If the user types a name in the list, use it. - * Once a name has been selected, prompt for a donation amount. - * Verify that the amount is in fact a number, and re-prompt if it isn't. - * Once an amount has been given, add that amount to the donation history of - the selected user. - * Finally, use string formatting to compose an email thanking the donor for - their generous donation. Print the email to the terminal and return to the - original prompt. +Think Python: Chapters 11, 13, 14 -**It is fine to forget new donors once the script quits running.** +Learn Python the Hard way: 15-17, 39 -.. nextslide:: Creating a Report +Dive Into Python3: Sections 2.6, 2.7, 11 -* If the user (you) selected 'Create a Report' Print a list of your donors, - sorted by total historical donation amount. +Next Week: +=========== - - Include Donor Name, total donated, number of donations and average donation - amount as values in each row. - - Using string formatting, format the output rows as nicely as possible. The - end result should be tabular (values in each column should align with those - above and below) - - After printing this report, return to the original prompt. +.. rst-class:: mlarge -* At any point, the user should be able to quit their current task and return - to the original prompt. + **Lightning talks next week:** -* From the original prompt, the user should be able to quit the script cleanly +Abdishu Hagi -.. nextslide:: Guidelines +Enrique R Silva -First, factor your script into separate functions. Each of the above -tasks can be accomplished by a series of steps. Write discreet functions -that accomplish individual steps and call them. +Isaac Cowhey -Second, use loops to control the logical flow of your program. Interactive -programs are a classic use-case for the ``while`` loop. +Paul G Anderson -Put the functions you write into the script at the top. -Put your main interaction into an ``if __name__ == '__main__'`` block. -Finally, use only functions and the basic Python data types you've learned -about so far. There is no need to go any farther than that for this assignment. -.. nextslide:: Submission -As always, put the new file in your student directory in a ``session03`` -directory, and add it to your clone early. Make frequent commits with -good, clear messages about what you are doing and why. -When you are done, push your changes and make a pull request. diff --git a/_sources/session04.txt b/_sources/session04.txt new file mode 100644 index 00000000..77ee3d1d --- /dev/null +++ b/_sources/session04.txt @@ -0,0 +1,1010 @@ +.. include:: include.rst + +******************************************* +Session Four: Dictionaries, Sets, and Files +******************************************* + +================ +Review/Questions +================ + +Review of Previous Classes +-------------------------- + + * Sequences + + - Slicing + - Lists + - Tuples + - tuple vs lists - which to use? + + * interating + + - for + - while + + - break and continue + + - else with loops + +Any questions? + +Lightning Talks Today: +---------------------- + +.. rst-class:: medium + + Abdishu Hagi + + Enrique R Silva + + Isaac Cowhey + + Paul G Anderson + + +============================== +Handy hints for/from Homework +============================== + +.. rst-class:: mlarge + + You almost never need to loop through the indexes of a sequence + +nifty for loop tricks +--------------------- + +**tuple unpacking:** + +remember this? + +.. code-block:: python + + x, y = 3, 4 + +You can do that in a for loop, also: + +.. code-block:: ipython + + In [4]: l = [(1, 2), (3, 4), (5, 6)] + + In [5]: for i, j in l: + print("i:{}, j:{}".format(i, j)) + + i:1, j:2 + i:3, j:4 + i:5, j:6 + +(Mailroom example) + + +Looping through two iterables at once: +-------------------------------------- + +.. rst-class:: mlarge + + ``zip`` + +.. code-block:: ipython + + In [10]: l1 = [1, 2, 3] + + In [11]: l2 = [3, 4, 5] + + In [12]: for i, j in zip(l1, l2): + print("i:{}, j:{}".format(i, j)) + + i:1, j:3 + i:2, j:4 + i:3, j:5 + +Can be more than two: + +.. code-block:: python + + for i, j, k, l in zip(l1, l2, l3, l4): + + +Need the index and the item? +---------------------------- + +.. rst-class:: mlarge + + ``enumerate`` + +.. code-block:: ipython + + In [2]: l = ['this', 'that', 'the other'] + + In [3]: for i, item in enumerate(l): + ...: print("the {:d}th item is: {:s}".format(i, item)) + ...: + the 0th item is: this + the 1th item is: that + the 2th item is: the other + + + +Homework Comments +----------------- + +Building up a long string. + +The obvious thing to do is something like:: + + msg = "" + for piece in list_of_stuff: + msg += piece + +But: strings are immutable -- python needs to create a new string each time you add a piece -- not efficient:: + + msg = [] + for piece in list_of_stuff: + msg.append(piece) + " ".join(msg) + +appending to lists is efficient -- and so is the join() method of strings. + +.. nextslide:: + +.. rst-class:: center mlarge + +You can put a mutable item in an immutable object! + +(demo) + +.. nextslide:: A couple small things: + +| +| Use string formatting +| +| The ``sum()`` function +| +| Deleting from list (list_lab) +| + +__main__ +-------- + +What is this:: + + if __name__ == __main__ + +about? + +Every module has a __name__ + +If the module is loaded by ``import`` then it's name is the filename. + +If the module is run at the command line, like: + +.. code-block:: bash + + python3 the_module.py + +Then it's ``__name__`` will be "__main__" + +This can be used to run code only when a module is run as a command, +but not when it is imported. + +(demo) + +assert +------ + +What is ``assert`` for? + +Testing -- NOT for issues expected to happen operationally:: + + assert m >= 0 + +in operational code should be:: + + if m < 0: + raise ValueError + +I'll cover more next week ... + +(Asserts get ignored if optimization is turned on!) + +what the heck is reversed()? +---------------------------- + +I had a question in a PR: + +"what is ``reversed(x)``'s resultant object? what good is it?"" + +.. nextslide:: + +try it: + +.. code-block:: ipython + + In [14]: type(reversed(l)) + Out[14]: list_reverseiterator + +so it's a ``list_reverseiterator`` object -- not helpful, is it :-) + +But what it means is that it's an "iterable" that you can then do things like loop through with a for loop, etc. but it hasn't made a copy of the list -- it returns the items one by one as they are asked for. this has performance benefits, as it doesn't have to make a copy of the whole thing. + +So you use it if you want to loop through something in reversed order, but dont actually need an actual list with the order reversed. + +we'll get more into the details of iterators and iterables later in the class. + +================= +A little warm up +================= + +Fun with strings +------------------ + +* Rewrite: ``the first 3 numbers are: %i, %i, %i"%(1,2,3)`` + + - for an arbitrary number of numbers... + +=============== +Lightning Talks +=============== + +| +| Isaac Cowhey +| +| Paul G Anderson +| + +===================== +Dictionaries and Sets +===================== + +Dictionary +---------- +Python calls it a ``dict`` + +Other languages call it: + + * dictionary + * associative array + * map + * hash table + * hash + * key-value pair + + +Dictionary Constructors +----------------------- +.. code-block:: python + + >>> {'key1': 3, 'key2': 5} + {'key1': 3, 'key2': 5} + + >>> dict([('key1', 3),('key2', 5)]) + {'key1': 3, 'key2': 5} + + >>> dict(key1=3, key2= 5) + {'key1': 3, 'key2': 5} + + >>> d = {} + >>> d['key1'] = 3 + >>> d['key2'] = 5 + >>> d + {'key1': 3, 'key2': 5} + +Dictionary Indexing +------------------- +:: + + >>> d = {'name': 'Brian', 'score': 42} + + >>> d['score'] + 42 + + >>> d = {1: 'one', 0: 'zero'} + + >>> d[0] + 'zero' + + >>> d['non-existing key'] + Traceback (most recent call last): + File "", line 1, in + KeyError: 'non-existing key' + + +.. nextslide:: + +Keys can be any immutable: + + * number + * string + * tuple + +.. code-block:: ipython + + In [325]: d[3] = 'string' + In [326]: d[3.14] = 'pi' + In [327]: d['pi'] = 3.14 + In [328]: d[ (1,2,3) ] = 'a tuple key' + In [329]: d[ [1,2,3] ] = 'a list key' + TypeError: unhashable type: 'list' + + +Actually -- any "hashable" type. + + +.. nextslide:: Hashing + +Hash functions convert arbitrarily large data to a small proxy (usually int) + +Always return the same proxy for the same input + +MD5, SHA, etc + +Dictionaries hash the key to an integer proxy and use it to find the key and value. + +Key lookup is efficient because the hash function leads directly to a bucket with very few keys (often just one) + +What would happen if the proxy changed after storing a key? + +Hashability requires immutability + +Key lookup is very efficient + +Same average time regardless of size + + +.. nextslide:: Dictionary indexing + + +Note: Python name look-ups are implemented with dict -- it's highly optimized + +Key to value: + + * lookup is one way + +Value to key: + + * requires visiting the whole dict + +If you need to check dict values often, create another dict or set + +(up to you to keep them in sync) + + +Dictionary Ordering (not) +------------------------- + + +Dictionaries have no defined order + +.. code-block:: ipython + + In [352]: d = {'one':1, 'two':2, 'three':3} + In [353]: d + Out[353]: {'one': 1, 'three': 3, 'two': 2} + In [354]: d.keys() + Out[354]: dict_keys(['three', 'two', 'one']) + +Dictionary Iterating +-------------------- + +``for`` iterates over the keys + +.. code-block:: ipython + + In [15]: d = {'name': 'Brian', 'score': 42} + + In [16]: for x in d: + print(x) + ....: + score + name + + +(note the different order...) + +dict keys and values +-------------------- + +.. code-block:: ipython + + In [20]: d = {'name': 'Brian', 'score': 42} + + In [21]: d.keys() + Out[21]: dict_keys(['score', 'name']) + + In [22]: d.values() + Out[22]: dict_values([42, 'Brian']) + + In [23]: d.items() + Out[23]: dict_items([('score', 42), ('name', 'Brian')]) + + +dict keys and values +-------------------- + +Iterating on everything + +.. code-block:: ipython + + In [26]: d = {'name': 'Brian', 'score': 42} + + In [27]: for k, v in d.items(): + print("%s: %s" % (k,v)) + ....: + score: 42 + name: Brian + + +Dictionary Performance +----------------------- + + * indexing is fast and constant time: O(1) + + * ``x in s`` constant time: O(1) + + * visiting all is proportional to n: O(n) + + * inserting is constant time: O(1) + + * deleting is constant time: O(1) + + + http://wiki.python.org/moin/TimeComplexity + + +Other dict operations: +---------------------- + +See them all here: + +https://docs.python.org/3/library/stdtypes.html#mapping-types-dict + +Is it in there? + +.. code-block:: ipython + + In [5]: d + Out[5]: {'that': 7, 'this': 5} + + In [6]: 'that' in d + Out[6]: True + + In [7]: 'this' not in d + Out[7]: False + +Containment is on the keys. + +.. nextslide:: + +Getting something: (like indexing) + +.. code-block:: ipython + + In [9]: d.get('this') + Out[9]: 5 + +But you can specify a default + +.. code-block:: ipython + + In [11]: d.get('something', 'a default') + Out[11]: 'a default' + +Never raises an Exception (default default is None) + +.. nextslide:: + +iterating + +.. code-block:: ipython + + In [13]: for item in d: + ....: print(item) + ....: + this + that + +which is equivalent to, but faster than: + +.. code-block:: ipython + + In [15]: for key in d.keys(): + print(key) + ....: + this + that + +.. nextslide:: + +but to get values, must specify you want values: + +.. code-block:: ipython + + In [16]: for val in d.values(): + print(val) + ....: + 5 + 7 + + +.. nextslide:: + +"Popping": getting the value while removing it + +pop out a particular key + +.. code-block:: ipython + + In [19]: d.pop('this') + Out[19]: 5 + + In [20]: d + Out[20]: {'that': 7} + +pop out an arbitrary key, value pair + +.. code-block:: ipython + + In [23]: d.popitem() + Out[23]: ('that', 7) + + In [24]: d + Out[24]: {} + +.. nextslide:: + +This one is handy: + +``setdefault(key[, default])`` + +gets the value if it's there, sets it if it's not + +.. code-block:: ipython + + In [27]: d.setdefault('something', 'a value') + Out[27]: 'a value' + + In [28]: d + Out[28]: {'something': 'a value'} + + +.. nextslide:: + +Assignment maintains link to the original dict + +.. code-block:: ipython + + In [47]: d + Out[47]: {'something': 'a value'} + + In [48]: item_view = d + + In [49]: d['something else'] = 'another value' + + In [50]: item_view + Out[50]: {'something': 'a value', 'something else': 'another value'} + + +.. nextslide:: + +Use explicit copy method to get a copy + +.. code-block:: ipython + + In [51] item_copy = d.copy() + + In [52]: d['another thing'] = 'different value' + + In [53]: d + Out[53]: + {'another thing': 'different value', + 'something': 'a value', + 'something else': 'another value'} + + In [54]: item_copy + Out[54]: {'something': 'a value', 'something else': 'another value'} + + +Sets +----- + +``set`` is an unordered collection of distinct values + +Essentially a dict with only keys + +Set Constructors + +.. code-block:: ipython + + >>> set() + set() + + >>> set([1, 2, 3]) + {1, 2, 3} + + >>> {1, 2, 3} + {1, 2, 3} + + >>> s = set() + + >>> s.update([1, 2, 3]) + >>> s + {1, 2, 3} + + +Set Properties +--------------- + +``Set`` members must be hashable + +Like dictionary keys -- and for same reason (efficient lookup) + +No indexing (unordered) + +.. code-block:: ipython + + >>> s[1] + Traceback (most recent call last): + File "", line 1, in + TypeError: 'set' object does not support indexing + + +Set Methods +----------- + +.. code-block:: ipython + + >> s = set([1]) + >>> s.pop() # an arbitrary member + 1 + >>> s.pop() + Traceback (most recent call last): + File "", line 1, in + KeyError: 'pop from an empty set' + >>> s = set([1, 2, 3]) + >>> s.remove(2) + >>> s.remove(2) + Traceback (most recent call last): + File "", line 1, in + KeyError: 2 + +.. nextslide:: + +All the "set" operations from math class... + +.. code-block:: python + + s.isdisjoint(other) + + s.issubset(other) + + s.union(other, ...) + + s.intersection(other, ...) + + s.difference(other, ...) + + s.symmetric_difference( other, ...) + +Frozen Set +---------- + +Another kind of set: ``frozenset`` + +immutable -- for use as a key in a dict +(or another set...) + +.. code-block:: python + + >>> fs = frozenset((3,8,5)) + >>> fs.add(9) + Traceback (most recent call last): + File "", line 1, in + AttributeError: 'frozenset' object has no attribute 'add' + + +LAB: Dictionaries and Sets lab +============================== + +Have some fun with dictionaries and sets! + +:ref:`exercise_dict_lab` + + +Lightning Talks +--------------- + +| +| Abdishu Hagi +| +| Enrique R Silva +| + +======================== +File Reading and Writing +======================== + +Files +----- + +Text Files + +.. code-block:: python + + f = open('secrets.txt') + secret_data = f.read() + f.close() + +``secret_data`` is a string + +NOTE: these days, you probably need to use Unicode for text -- we'll get to that next week + +.. nextslide:: + +Binary Files + +.. code-block:: python + + f = open('secrets.bin', 'rb') + secret_data = f.read() + f.close() + +``secret_data`` is a byte string + +(with arbitrary bytes in it -- well, not arbitrary -- whatever is in the file.) + +(See the ``struct`` module to unpack binary data ) + + +.. nextslide:: + + +File Opening Modes + +.. code-block:: python + + f = open('secrets.txt', [mode]) + 'r', 'w', 'a' + 'rb', 'wb', 'ab' + r+, w+, a+ + r+b, w+b, a+b + + +These follow the Unix conventions, and aren't all that well documented +in the Python docs. But these BSD docs make it pretty clear: + +http://www.manpagez.com/man/3/fopen/ + +**Gotcha** -- 'w' modes always clear the file + +.. nextslide:: Text File Notes + +Text is default + + * Newlines are translated: ``\r\n -> \n`` + * -- reading and writing! + * Use \*nix-style in your code: ``\n`` + + +Gotcha: + + * no difference between text and binary on \*nix + * breaks on Windows + + +File Reading +------------ + +Reading part of a file + +.. code-block:: python + + header_size = 4096 + f = open('secrets.txt') + secret_header = f.read(header_size) + secret_rest = f.read() + f.close() + +.. nextslide:: + + +Common Idioms + +.. code-block:: python + + for line in open('secrets.txt'): + print(line) + +(the file object is an iterator!) + +.. code-block:: python + + f = open('secrets.txt') + while True: + line = f.readline() + if not line: + break + do_something_with_line() + +.. nextslide:: + +We will learn more about the keyword with later, but for now, just understand +the syntax and the advantage over the try-finally block: + +.. code-block:: python + + with open('workfile', 'r') as f: + read_data = f.read() + f.closed + True + + +File Writing +------------ + +.. code-block:: python + + outfile = open('output.txt', 'w') + for i in range(10): + outfile.write("this is line: %i\n"%i) + outfile.close() + + with open('output.txt', 'w'): + for i in range(10): + f.write("this is line: %i\n"%i) + + +File Methods +------------ + +Commonly Used Methods + +.. code-block:: python + + f.read() f.readline() f.readlines() + + f.write(str) f.writelines(seq) + + f.seek(offset) f.tell() # for binary files, mostly + + f.close() + +StringIO +-------- + +.. code-block:: python + + In [417]: import io + In [420]: f = io.StringIO() + In [421]: f.write("somestuff") + In [422]: f.seek(0) + In [423]: f.read() + Out[423]: 'somestuff' + Out[424]: stuff = f.getvalue() + Out[425]: f.close() + +(handy for testing file handling code...) + +There is also cStringIO -- a bit faster. + +.. code-block:: python + + from cStringIO import StringIO + +===================== +Paths and Directories +===================== + +Paths +----- + +Paths are generally handled with simple strings (or Unicode strings) + +Relative paths: + +.. code-block:: python + + 'secret.txt' + './secret.txt' + +Absolute paths: + +.. code-block:: python + + '/home/chris/secret.txt' + + +Either work with ``open()`` , etc. + +(working directory only makes sense with command-line programs...) + +os module +---------- + +.. code-block:: python + + os.getcwd() + os.chdir(path) + os.path.abspath() + os.path.relpath() + + +.. nextslide:: os.path module + +.. code-block:: python + + os.path.split() + os.path.splitext() + os.path.basename() + os.path.dirname() + os.path.join() + + +(all platform independent) + +.. nextslide:: directories + +.. code-block:: python + + os.listdir() + os.mkdir() + os.walk() + +(higher level stuff in ``shutil`` module) + +pathlib +------- + +``pathlib`` is a package for handling paths in an OO way: + +http://pathlib.readthedocs.org/en/pep428/ + +All the stuff in os.path and more: + +.. code-block:: ipython + + In [64]: import pathlib + In [65]: pth = pathlib.Path('./') + In [66]: pth.is_dir() + Out[66]: True + In [67]: pth.absolute() + Out[67]: PosixPath('/Users/Chris/PythonStuff/UWPCE/IntroPython2015') + In [68]: for f in pth.iterdir(): + print(f) + junk2.txt + junkfile.txt + ... + +=== +LAB +=== + +Files Lab: If there is time. + +:ref:`exercise_file_lab` + + + +========= +Homework +========= + +Recommended Reading: +--------------------- + + * Dive Into Python 3: Chapt. 2.7 (and 4 if you haven't already) + +http://www.diveintopython3.net/native-datatypes.html#dictionaries + + * Dive Into Python 3: Chapt. 11 + +http://www.diveintopython3.net/files.html + + +Assignments: +------------- + + * Finish the dict/sets lab: :ref:`exercise_dict_lab` + * Finish the files lab: :ref:`exercise_file_lab` + * Coding kata: trigrams: :ref:`exercise_trigrams` + + * update mailroom with dicts :ref:`exercise_mailroom_plus` diff --git a/_sources/session05.txt b/_sources/session05.txt new file mode 100644 index 00000000..04b21d7a --- /dev/null +++ b/_sources/session05.txt @@ -0,0 +1,776 @@ +.. include:: include.rst + +**************************************** +Session Five: Exceptions, Comprehensions +**************************************** + +====================== +Lightning Talks Today: +====================== + +.. rst-class:: medium + + Alexander C Truong + + Darryl Wong + + Madhumita Acharya + + Matthew T Weidner + +================ +Review/Questions +================ + +Review of Previous Class +------------------------ + + * Dictionaries + * Sets + * File processing, etc. + +.. nextslide:: + +.. rst-class:: center large + + How many of you finished ALL the homework? + +.. nextslide:: + +.. rst-class:: center large + + Sorry about that! + +.. nextslide:: + +.. rst-class:: medium + + * That was a lot. + +.. rst-class:: medium + +.. rst-class:: build + + * But it's all good stuff. + + * I'll take time to go over it in class. + + * And this week is a light load, so you can catch up. + + +Homework review +--------------- + +My Solutions to all the exercises in the class repo in: + +``Solutions/Session04`` + +A few tidbits, then I'll take specific questions. + + +The count() method +------------------ + +All Python sequences (including strings) have a ``count()`` method: + +.. code-block:: ipython + + In [1]: s = "This is an arbitrary string" + + In [2]: s.count('t') + Out[2]: 2 + +What if you want a case-insensitive count? + +.. code-block:: ipython + + In [3]: s.lower().count('t') + Out[3]: 3 + +set.update() +------------ + +If you want to add a bunch of stuff to a set, you can use update: + +.. code-block:: ipython + + In [1]: s = set() + +In [2]: s.update +Out[2]: + +In [3]: s.update(['this', 'that']) + +In [4]: s +Out[4]: {'that', 'this'} + +In [5]: s.update(['this', 'thatthing']) + +In [6]: s +Out[6]: {'that', 'thatthing', 'this'} + +**NOTE:** It's VERY often the case that when you find yourself writing a trivial loop -- there is a way to do it with a built in method! + + + +Sorting stuff in dictionaries: +------------------------------- + +dicts aren't sorted, so what if you want to do something in a sorted way? + +The "standard" way: + +.. code-block:: python + + for key in sorted(d.keys()): + ... + +Another option: + +.. code-block:: python + + collections.OrderedDict + +Also other nifty stuff in the ``collections`` module: + +https://docs.python.org/3.5/library/collections.html + +Using files and "with" +----------------------- + +Sorry for the confusion, but I'll be more clear now. + +When working with files, unless you have a good reason not to, use ``with``: + +.. code-block:: python + + with open(the_filename, 'w') as outfile: + outfile.write(something) + do_some_more... + # now done with out file -- it will be closed, regardless of errors, etc. + do_other_stuff + +``with`` invokes a context manager -- which can be confusing, but for now, +just follow this pattern -- it really is more robust. + +And you can even do two at once: + +.. code-block:: python + + with open(source, 'rb') as infile, open(dest, 'wb') as outfile: + outfile.write(infile.read()) + + +Binary files +------------ + +Python can open files in one of two modes: + + * Text + * Binary + +This is just what you'd think -- if the file contains text, you want text mode. If the file contains arbitrary binary data, you want binary mode. + +All data in all files is binary -- that's how computers work. So in Python3, "text" actually means Unicode -- which is a particular system for matching characters to binary data. + +But this too is complicated -- there are multiple ways that binary data can be mapped to Unicode text, known as "encodings". In Python, text files are by default opened with the "utf-8" encoding. These days, that mostly "just works". + +.. nextslide:: + +But if you read a binary file as text, then Python will try to interpret the bytes as utf-8 encoded text -- and this will likely fail: + +.. code-block:: ipython + + In [13]: open("a_photo.jpg").read() + --------------------------------------------------------------------------- + UnicodeDecodeError Traceback (most recent call last) + in () + ----> 1 open("PassportPhoto.JPG").read() + + /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/codecs.py in decode(self, input, final) + 319 # decode input (taking the buffer into account) + 320 data = self.buffer + input + --> 321 (result, consumed) = self._buffer_decode(data, self.errors, final) + 322 # keep undecoded input until the next call + 323 self.buffer = data[consumed:] + + UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte + +.. nextslide:: + +In Python2, it's less likely that you'll get an error like this -- it doesn't try to decode the file as it's read -- even for text files -- so it's a bit tricky and more error prone. + +**NOTE:** If you want to actually DO anything with a binary file, other than passing it around, then you'll need to know a lot about how the details of what the bytes in the file mean -- and most likely, you'll use a library for that -- like an image processing library for the jpeg example above. + + +PEP 8 reminder +-------------- + +PEP 8 (Python Enhancement Proposal 8): https://www.python.org/dev/peps/pep-0008/ + +Is the "official" style guide for Python code. + +Strictly speaking, you only need to follow it for code in the standard library. + +But style matters -- consistent style makes your code easier to read and understand. + +So **follow PEP 8** + +**Exception:** if you have a company style guide -- follow that instead. + +Try the "pycodestyle" module on your code:: + + $ python3 -m pip install pycodestyle + $ pycodestyle my_python_file + +(demo) + +Naming things... +---------------- + +It matters what names you give your variables. + +Python has rules about what it *allows* + +PEP8 has rules for style: capitalization, and underscores and all that. + +But you still get to decide within those rules. + +So use names that make sense to the reader. + +Naming Guidelines +----------------- + +Only use single-letter names for things with limited scope: indexes and the like: + +.. code-block:: python + + for i, item in enumerate(a_sequence): + do_something(i, item) + +**Don't** use a name like "item", when there is a meaning to what the item is: + +.. code-block:: python + + for name in all_the_names: + do_something_with(name) + +Use plurals for collections of things: + +.. code-block:: python + + names = ['Fred', 'George', ...] + +.. nextslide:: + +**Do** re-use names when the use is essentially the same, and you don't need the old one: + +.. code-block:: python + + line = line.strip() + line = line.replace(",", " ") + .... + +Here's a nice talk about naming: + +http://pyvideo.org/video/3792/name-things-once-0 + + +Code Review +------------ + +.. rst-class:: center medium + +Anyone stuck or confused that's willing to volunteer for a live code review? + +My Solutions +------------- + +Anyone look at my solutions? + +(yeah, not much time for that...) + +Anything in particular you'd like me to go over? + + +trigrams +-------- + +Let's take a close look at trigrams! + +Some of you have already done a nice solution to this. + +But some of you are not sure how to start. + +So let's start from the beginning... + +NOTE: think about set vs list. + +(demo) + +Lightning Talks +---------------- + +.. rst-class:: medium + +| +| Alexander C Truong +| +| +| Darryl Wong +| + +========== +Exceptions +========== + +A really nifty python feature -- really handy! + +Exceptions +---------- + +Another Branching structure: + +.. code-block:: python + + try: + do_something() + f = open('missing.txt') + process(f) # never called if file missing + except IOError: + print("couldn't open missing.txt") + +Exceptions +---------- + +Never Do this: + +.. code-block:: python + + try: + do_something() + f = open('missing.txt') + process(f) # never called if file missing + except: + print "couldn't open missing.txt" + +**always** capture the *particular* Exception you know how to handle. + + +Exceptions +---------- + +Use Exceptions, rather than your own tests: + +Don't do this: + +.. code-block:: python + + do_something() + if os.path.exists('missing.txt'): + f = open('missing.txt') + process(f) + +It will almost always work -- but the almost will drive you crazy + +.. nextslide:: + +Example from homework + +.. code-block:: python + + if num_in.isdigit(): + num_in = int(num_in) + +but -- ``int(num_in)`` will only work if the string can be converted to an integer. + +So you can do + +.. code-block:: python + + try: + num_in = int(num_in) + except ValueError: + print("Input must be an integer, try again.") + +Or let the Exception be raised.... + + +EAFP +---- + + +"it's Easier to Ask Forgiveness than Permission" + + -- Grace Hopper + + +http://www.youtube.com/watch?v=AZDWveIdqjY + +(PyCon talk by Alex Martelli) + + +.. nextslide:: Do you catch all Exceptions? + +For simple scripts, let exceptions happen. + +Only handle the exception if the code can and will do something about it. + +(much better debugging info when an error does occur) + + +Exceptions -- finally +--------------------- + +.. code-block:: python + + try: + do_something() + f = open('missing.txt') + process(f) # never called if file missing + except IOError: + print("couldn't open missing.txt") + finally: + do_some_clean-up + +The ``finally:`` clause will always run + + +Exceptions -- else +------------------- + +.. code-block:: python + + try: + do_something() + f = open('missing.txt') + except IOError: + print("couldn't open missing.txt") + else: + process(f) # only called if there was no exception + +Advantage: + +you know where the Exception came from + +Exceptions -- using them +------------------------ + +.. code-block:: python + + try: + do_something() + f = open('missing.txt') + except IOError as the_error: + print(the_error) + the_error.extra_info = "some more information" + raise + + +Particularly useful if you catch more than one exception: + +.. code-block:: python + + except (IOError, BufferError, OSError) as the_error: + do_something_with (the_error) + + +Raising Exceptions +------------------- + +.. code-block:: python + + def divide(a,b): + if b == 0: + raise ZeroDivisionError("b can not be zero") + else: + return a / b + + +when you call it: + +.. code-block:: ipython + + In [515]: divide (12,0) + ZeroDivisionError: b can not be zero + + +Built in Exceptions +------------------- + +You can create your own custom exceptions + +But... + +.. code-block:: python + + exp = \ + [name for name in dir(__builtin__) if "Error" in name] + len(exp) + 32 + + +For the most part, you can/should use a built in one + +.. nextslide:: + +Choose the best match you can for the built in Exception you raise. + +Example (from last week's exercises):: + + if (not isinstance(m, int)) or (not isinstance(n, int)): + raise ValueError + +Is it the *value* or the input the problem here? + +Nope: the *type* is the problem:: + + if (not isinstance(m, int)) or (not isinstance(n, int)): + raise TypeError + +but should you be checking type anyway? (EAFP) + +=== +LAB +=== + +Exceptions Lab: + + +:ref:`exercise_exceptions_lab` + + +Lightning Talks +--------------- + +.. rst-class:: medium + +| +| Madhumita Acharya +| +| Matthew T Weidner + + + +============================ +List and Dict Comprehensions +============================ + +List comprehensions +------------------- + +A bit of functional programming + +consider this common ``for`` loop structure: + +.. code-block:: python + + new_list = [] + for variable in a_list: + new_list.append(expression) + +This can be expressed with a single line using a "list comprehension" + +.. code-block:: python + + new_list = [expression for variable in a_list] + + +.. nextslide:: + +What about nested for loops? + +.. code-block:: python + + new_list = [] + for var in a_list: + for var2 in a_list2: + new_list.append(expression) + +Can also be expressed in one line: + +.. code-block:: python + + new_list = [exp for var in a_list for var2 in a_list2] + +You get the "outer product", i.e. all combinations. + +(demo) + +.. nextslide:: + +But usually you at least have a conditional in the loop: + +.. code-block:: python + + new_list = [] + for variable in a_list: + if something_is_true: + new_list.append(expression) + +You can add a conditional to the comprehension: + +.. code-block:: python + + new_list = [expr for var in a_list if something_is_true] + + +(demo) + +.. nextslide:: + +Examples: + +.. code-block:: ipython + + In [341]: [x**2 for x in range(3)] + Out[341]: [0, 1, 4] + + In [342]: [x+y for x in range(3) for y in range(5,7)] + Out[342]: [5, 6, 6, 7, 7, 8] + + In [343]: [x*2 for x in range(6) if not x%2] + Out[343]: [0, 4, 8] + + + +.. nextslide:: + +Remember this from earlier today? + +.. code-block:: python + + [name for name in dir(__builtin__) if "Error" in name] + ['ArithmeticError', + 'AssertionError', + 'AttributeError', + 'BufferError', + 'EOFError', + .... + + +Set Comprehensions +------------------ + +You can do it with sets, too: + +.. code-block:: python + + new_set = { value for variable in a_sequence } + + +same as for loop: + +.. code-block:: python + + new_set = set() + for key in a_list: + new_set.add(value) + + +.. nextslide:: + +Example: finding all the vowels in a string... + +.. code-block:: ipython + + In [19]: s = "a not very long string" + + In [20]: vowels = set('aeiou') + + In [21]: { l for l in s if l in vowels } + Out[21]: {'a', 'e', 'i', 'o'} + +Side note: why did I do ``set('aeiou')`` rather than just `aeiou` ? + + +Dict Comprehensions +------------------- + +Also with dictionaries + +.. code-block:: python + + new_dict = { key:value for variable in a_sequence} + + +same as for loop: + +.. code-block:: python + + new_dict = {} + for key in a_list: + new_dict[key] = value + + + +.. nextslide:: + +Example + +.. code-block:: ipython + + In [22]: { i: "this_%i"%i for i in range(5) } + Out[22]: {0: 'this_0', 1: 'this_1', 2: 'this_2', + 3: 'this_3', 4: 'this_4'} + + +(not as useful with the ``dict()`` constructor...) + +=== +LAB +=== + +Here is a nice tutorial on list comprehensions: + +http://treyhunner.com/2015/12/python-list-comprehensions-now-in-color/ + +List comps exercises: + +:ref:`exercise_comprehensions` + + + +========= +Homework +========= + +Catch up! +--------- + +* Finish the LABs from today + - Exceptions lab + +* Catch up from last week. + + - Add Exception handling to mailroom + - And list (and dict, and set) comprehensions... + +* If you've done all that -- check out the collections module: + + - https://docs.python.org/3.5/library/collections.html + - here's a good overview: https://pymotw.com/3/collections/ + +==================================== +Material to review before next week: +==================================== + +**Unit Testing:** + +* Dive into Python: chapter 9: + http://www.diveintopython3.net/unit-testing.html + +NOTE: you will find that most introductions to unit testing with Python use the builtin ``unitest`` module. However, it is a bit heavyweight, and requires some knowledge of OOP -- classes, etc. So we'll be using pytest in this class: http://doc.pytest.org/en/latest/. But the principles of testing are the same. + +* Ned Batchelder's intro to testing presentation: + + - http://nedbatchelder.com/text/test0.html + +** Advanced Argument Passing + +* arguments and parameters: + + - http://stupidpythonideas.blogspot.com/2013/08/arguments-and-parameters.html + + - https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/ + diff --git a/_sources/session06.txt b/_sources/session06.txt new file mode 100644 index 00000000..d5e624b9 --- /dev/null +++ b/_sources/session06.txt @@ -0,0 +1,834 @@ +.. include:: include.rst + +*********************************************** +Session Six: Testing, Advanced Argument Passing +*********************************************** + +====================== +Lightning Talks Today: +====================== + +.. rst-class:: medium + + Adam Hollis + + Nachiket Galande + + Paul A Casey + +================ +Review/Questions +================ + +Review of Previous Class +------------------------ + +* Exceptions + +* Comprehensions + + +=============== +Homework review +=============== + +Homework Questions? + +Notes from Homework: +-------------------- + +Comparing to "singletons": + +Use: + +``if something is None`` + +Not: + +``if something == None`` + +(also ``True`` and ``False``) + +rich comparisons: numpy + +(demo) + +.. nextslide:: + +You don't actually need to use the result of a list comp: + +.. code-block:: python + + for i, st in zip( divisors, sets): + [ st.add(j) for j in range(21) if not j%i ] + +.. nextslide:: + +Python functions are objects, so if you don't call them, you don't get an error, you just get the function object, usually not what you want:: + + elif donor_name.lower == "exit": + +this is comparing the string ``lower`` method to the string "exit" and they are never going to be equal! + +That should be:: + + elif donor_name.lower() == "exit": + +This is actually a pretty common typo -- keep an eye out for it when you get strange errors, or something just doesn't seem to be getting triggered. + +long strings +------------ + +if you need to do along string literal, sometimes a triple quoted string is perfect:: + + """this is a long string. + I want it to hvae multiple lines. + so having the line endings automatic is great. + """ + +But you don't always want the line endings quite like that. And you may not want all that whitespace when fitting it into indented code. + +It turns out that when you put a multiple strings together with no commas or anythign in between -- python will join them: + +.. code-block:: ipython + + In [81]: "this is " "a string " "built up of parts" + Out[81]: 'this is a string built up of parts' + +.. nextslide:: + +If it's in parentheses, you can put the next chunk on the next line: + +.. code-block:: python + + print("{} is from {}, and he likes " + "{} cake, {} fruit, {} salad, " + "and {} pasta.".format(food_prefs["name"], + food_prefs["city"], + food_prefs["cake"], + food_prefs["fruit"], + food_prefs["salad"], + food_prefs["pasta"])) + +pretty print +------------ + +If you need to print our nested (or large) data structure in a more readable fashion, the "pretty print" module is handy: + +.. code-block:: ipython + + from pprint import pprint + + In [28]: print(food_prefs) + {'pasta': 'lasagna', 'cake': 'chocolate', 'salad': 'greek', 'fruit': 'mango', 'name': 'Chris', 'city': 'Seattle'} + + In [29]: pprint(food_prefs) + {'cake': 'chocolate', + 'city': 'Seattle', + 'fruit': 'mango', + 'name': 'Chris', + 'pasta': 'lasagna', + 'salad': 'greek'} + +Exceptions +---------- + +Adding stuff to an Exception: + +Example from slack + + +Anything else? +-------------- + +.. rst-class:: center medium + + Anything else you want me to go over? + + +Lightning Talks +---------------- + +.. rst-class:: medium + +| +| Adam Hollis +| +| Nachiket Galande +| + +======= +Testing +======= + +.. rst-class:: build left +.. container:: + + You've already seen a very basic testing strategy. + + You've written some tests using that strategy. + + These tests were pretty basic, and a bit awkward in places (testing error + conditions in particular). + + .. rst-class:: centered large + + **It gets better** + +Test Runners +------------ + +So far our tests have been limited to code in an ``if __name__ == "__main__":`` +block. + +.. rst-class:: build + +* They are run only when the file is executed +* They are always run when the file is executed +* You can't do anything else when the file is executed without running tests. + +.. rst-class:: build +.. container:: + + This is not optimal. + + Python provides testing systems to help. + + +Standard Library: ``unittest`` +------------------------------- + +The original testing system in Python. + +``import unittest`` + +More or less a port of ``Junit`` from Java + +A bit verbose: you have to write classes & methods + +(And we haven't covered that yet!) + + +Using ``unittest`` +------------------- + +You write subclasses of the ``unittest.TestCase`` class: + +.. code-block:: python + + # in test.py + import unittest + + class MyTests(unittest.TestCase): + def test_tautology(self): + self.assertEquals(1, 1) + +Then you run the tests by using the ``main`` function from the ``unittest`` +module: + +.. code-block:: python + + # in test.py + if __name__ == '__main__': + unittest.main() + +.. nextslide:: Testing Your Code + +This way, you can write your code in one file and test it from another: + +.. code-block:: python + + # in my_mod.py + def my_func(val1, val2): + return val1 * val2 + + # in test_my_mod.py + import unittest + from my_mod import my_func + + class MyFuncTestCase(unittest.TestCase): + def test_my_func(self): + test_vals = (2, 3) + expected = reduce(lambda x, y: x * y, test_vals) + actual = my_func(*test_vals) + self.assertEquals(expected, actual) + + if __name__ == '__main__': + unittest.main() + +.. nextslide:: Advantages of ``unittest`` + +.. rst-class:: build +.. container:: + + The ``unittest`` module is pretty full featured + + It comes with the standard Python distribution, no installation required. + + It provides a wide variety of assertions for testing all sorts of situations. + + It allows for a setup and tear down workflow both before and after all tests and before and after each test. + + It's well known and well understood. + +.. nextslide:: Disadvantages: + +.. rst-class:: build +.. container:: + + + It's Object Oriented, and quite "heavyweight". + + - modeled after Java's ``junit`` and it shows... + + It uses the framework design pattern, so knowing how to use the features + means learning what to override. + + Needing to override means you have to be cautious. + + Test discovery is both inflexible and brittle. + + And there is no built-in parameterized testing. + +Other Options +------------- + +There are several other options for running tests in Python. + +* `Nose`: https://nose.readthedocs.org/ + +* `pytest`: http://pytest.org/latest/ + +* ... (many frameworks supply their own test runners: e.g. django) + +Both are very capable and widely used. I have a personal preference for pytest + +-- so we'll use it for this class + +Installing ``pytest`` +--------------------- + +The first step is to install the package: + +.. code-block:: bash + + $ python3 -m pip install pytest + +Once this is complete, you should have a ``py.test`` command you can run +at the command line: + +.. code-block:: bash + + $ py.test + +If you have any tests in your repository, that will find and run them. + +.. rst-class:: build +.. container:: + + **Do you?** + +Pre-existing Tests +------------------ + +Let's take a look at some examples. + +in ``IntroPython2016\Examples\Session06`` + +.. code-block:: bash + + $ py.test + +You can also run py.test on a particular test file: + +.. code-block:: bash + + $ py.test test_random_unitest.py + +The results you should have seen when you ran ``py.test`` above come +partly from these files. + +Let's take a few minutes to look these files over. + +[demo] + +What's Happening Here. +---------------------- + +When you run the ``py.test`` command, ``pytest`` starts in your current +working directory and searches the filesystem for things that might be tests. + +It follows some simple rules: + +* Any python file that starts with ``test_`` or ``_test`` is imported. + +* Any functions in them that start with ``test_`` are run as tests. + +* Any classes that start with ``Test`` are treated similarly, with methods that begin with ``test_`` treated as tests. + +( don't worry about "classes" part just yet ;-) ) + +pytest +------ + +This test running framework is simple, flexible and configurable. + +Read the documentation for more information: + +http://pytest.org/latest/getting-started.html#getstarted + +It will run ``unittest`` tests for you. + +But in addition to finding and running tests, it makes writting tests simple, and provides a bunch of nifty utilities to support more complex testing. + + +Test Driven Development +----------------------- +in the Examples dir, try:: + + $ py.test test_cigar_party + +What we've just done here is the first step in what is called: + +.. rst-class:: centered + + **Test Driven Development**. + +A bunch of tests exist, but the code to make them pass does not yet exist. + +The red you see in the terminal when we run our tests is a goad to us to write the code that fixes these tests. + +Let's do that next! + +Test Driven development demo +----------------------------- + +Open up: + +``Examples/Session06/test_cigar_party.py`` + +and: + +``Examples/Session06/cigar_party.py`` + +and run:: + + $ py.teset test_cigar_party.py + +Now go in to ``cigar_party.py`` and let's fix the tests. + +Let's play with codingbat.py also... + +=== +LAB +=== + +.. rst-class:: left + + Pick an example from codingbat: + + ``http://codingbat.com`` + + Do a bit of test-driven development on it: + + * run something on the web site. + * write a few tests using the examples from the site. + * then write the function, and fix it 'till it passes the tests. + + Do at least two of these... + +Lightning Talk +-------------- + +.. rst-class:: medium + + | + | Paul A Casey + | + +========================= +Advanced Argument Passing +========================= + +This is a very, very nifty Python feature -- it really lets you write dynamic programs. + +Keyword arguments +----------------- + +When defining a function, you can specify only what you need -- in any order + +.. code-block:: ipython + + In [151]: def fun(x=0, y=0, z=0): + print(x,y,z) + .....: + In [152]: fun(1,2,3) + 1 2 3 + In [153]: fun(1, z=3) + 1 0 3 + In [154]: fun(z=3, y=2) + 0 2 3 + + +.. nextslide:: + + +A Common Idiom: + +.. code-block:: python + + def fun(x, y=None): + if y is None: + do_something_different + go_on_here + + +.. nextslide:: + +Can set defaults to variables + +.. code-block:: ipython + + In [156]: y = 4 + In [157]: def fun(x=y): + print("x is:", x) + .....: + In [158]: fun() + x is: 4 + + +.. nextslide:: + +Defaults are evaluated when the function is defined + +.. code-block:: ipython + + In [156]: y = 4 + In [157]: def fun(x=y): + print("x is:", x) + .....: + In [158]: fun() + x is: 4 + In [159]: y = 6 + In [160]: fun() + x is: 4 + +This is a **very** important point -- I will repeat it! + + +Function arguments in variables +------------------------------- + +When a function is called, its arguments are really just: + +* a tuple (positional arguments) +* a dict (keyword arguments) + +.. code-block:: python + + def f(x, y, w=0, h=0): + print("position: {}, {} -- shape: {}, {}".format(x, y, w, h)) + + position = (3,4) + size = {'h': 10, 'w': 20} + + >>> f(*position, **size) + position: 3, 4 -- shape: 20, 10 + + +Function parameters in variables +-------------------------------- + +You can also pull the parameters out in the function as a tuple and a dict: + +.. code-block:: ipython + + def f(*args, **kwargs): + print("the positional arguments are:", args) + print("the keyword arguments are:", kwargs) + + In [389]: f(2, 3, this=5, that=7) + the positional arguments are: (2, 3) + the keyword arguments are: {'this': 5, 'that': 7} + +This can be very powerful... + +Passing a dict to str.format() +------------------------------- + +Now that you know that keyword args are really a dict, +you know how this nifty trick works: + +The string ``format()`` method takes keyword arguments: + +.. code-block:: ipython + + In [24]: "My name is {first} {last}".format(last="Barker", first="Chris") + Out[24]: 'My name is Chris Barker' + +Build a dict of the keys and values: + +.. code-block:: ipython + + In [25]: d = {"last":"Barker", "first":"Chris"} + +And pass to ``format()``with ``**`` + +.. code-block:: ipython + + In [26]: "My name is {first} {last}".format(**d) + Out[26]: 'My name is Chris Barker' + +Kinda handy for the dict lab, eh? + +This: + +.. code-block:: ipython + + print("{} is from {}, and he likes " + "{} cake, {} fruit, {} salad, " + "and {} pasta.".format(food_prefs["name"], + food_prefs["city"], + food_prefs["cake"], + food_prefs["fruit"], + food_prefs["salad"], + food_prefs["pasta"])) + +Becomes: + +.. code-block:: ipython + + print("{name} is from {city}, and he likes " + "{cake} cake, {fruit} fruit, {salad} salad, " + "and {pasta} pasta.".format(**food_prefs)) + +LAB +---- + +Time to play with all this to get a feel for it. + +:ref:`exercise_args_kwargs_lab` + +This is not all that clearly specified -- the goal is for you to +experiment with various ways to define and call functions, so you +can understand what's possible, and what happens with each call. + + +===================================== +A bit more on mutability (and copies) +===================================== + +mutable objects +---------------- + +We've talked about this: mutable objects can have their contents changed in place. + +Immutable objects can not. + +This has implications when you have a container with mutable objects in it: + +.. code-block:: ipython + + In [28]: list1 = [ [1,2,3], ['a','b'] ] + +one way to make a copy of a list: + +.. code-block:: ipython + + In [29]: list2 = list1[:] + + In [30]: list2 is list1 + Out[30]: False + +they are different lists. + +.. nextslide:: + +What if we set an element to a new value? + +.. code-block:: ipython + + In [31]: list1[0] = [5,6,7] + + In [32]: list1 + Out[32]: [[5, 6, 7], ['a', 'b']] + + In [33]: list2 + Out[33]: [[1, 2, 3], ['a', 'b']] + +So they are independent. + +.. nextslide:: + +But what if we mutate an element? + +.. code-block:: ipython + + In [34]: list1[1].append('c') + + In [35]: list1 + Out[35]: [[5, 6, 7], ['a', 'b', 'c']] + + In [36]: list2 + Out[36]: [[1, 2, 3], ['a', 'b', 'c']] + +uuh oh! mutating an element in one list mutated the one in the other list. + +.. nextslide:: + +Why is that? + +.. code-block:: ipython + + In [38]: list1[1] is list2[1] + Out[38]: True + +The elements are the same object! + +This is known as a "shallow" copy -- Python doesn't want to copy more than it needs to, so in this case, it makes a new list, but does not make copies of the contents. + +Same for dicts (and any container type -- even tuples!) + +If the elements are immutable, it doesn't really make a differnce -- but be very careful with mutable elements. + + +The copy module +---------------- + +most objects have a way to make copies (``dict.copy()`` for instance). + +but if not, you can use the ``copy`` module to make a copy: + +.. code-block:: ipython + + In [39]: import copy + + In [40]: list3 = copy.copy(list2) + + In [41]: list3 + Out[41]: [[1, 2, 3], ['a', 'b', 'c']] + +This is also a shallow copy. + +.. nextslide:: + +But there is another option: + +.. code-block:: ipython + + In [3]: list1 + Out[3]: [[1, 2, 3], ['a', 'b', 'c']] + + In [4]: list2 = copy.deepcopy(list1) + + In [5]: list1[0].append(4) + + In [6]: list1 + Out[6]: [[1, 2, 3, 4], ['a', 'b', 'c']] + + In [7]: list2 + Out[7]: [[1, 2, 3], ['a', 'b', 'c']] + +``deepcopy`` recurses through the object, making copies of everything as it goes. + +.. nextslide:: + + +I happened on this thread on stack overflow: + +http://stackoverflow.com/questions/3975376/understanding-dict-copy-shallow-or-deep + +The OP is pretty confused -- can you sort it out? + +Make sure you understand the difference between a reference, a shallow copy, and a deep copy. + +Mutables as default arguments: +------------------------------ + +Another "gotcha" is using mutables as default arguments: + +.. code-block:: ipython + + In [11]: def fun(x, a=[]): + ....: a.append(x) + ....: print(a) + ....: + +This makes sense: maybe you'd pass in a specific list, but if not, the default is an empty list. + +But: + +.. code-block:: ipython + + In [12]: fun(3) + [3] + + In [13]: fun(4) + [3, 4] + +Huh?! + +.. nextslide:: + +Remember that that default argument is defined when the function is created: there will be only one list, and every time the function is called, that same list is used. + + +The solution: + +The standard practice for such a mutable default argument: + +.. code-block:: ipython + + In [15]: def fun(x, a=None): + ....: if a is None: + ....: a = [] + ....: a.append(x) + ....: print(a) + In [16]: fun(3) + [3] + In [17]: fun(4) + [4] + +You get a new list every time the function is called + + +======== +Homework +======== + +.. rst-class:: left + + Finish up the Labs + + Write a complete set of unit tests for your mailroom program. + + * You will likely find that it is really hard to test without refactoring. + + * This is Good! + + * If code is hard to test -- it probably should be refactored. + + + +Material to review for next week +-------------------------------- + +Next week, we'll get started on Object Oriented Methods. It's a good idea to read up on it first -- so we can dive right in: + + * Dive into Python3: 7.2 -- 7.3 + http://www.diveintopython3.net/iterators.html#defining-classes + + * Think Python: 15 -- 18 + http://www.greenteapress.com/thinkpython/html/thinkpython016.html + + * LPTHW: 40 -- 44 + http://learnpythonthehardway.org/book/ex40.html + +[note that in py3 you don't need to inherit from object] + +Talk by Raymond Hettinger: + +Video of talk: https://youtu.be/HTLu2DFOdTg + +Slides: https://speakerdeck.com/pyconslides/pythons-class-development-toolkit-by-raymond-hettinger + diff --git a/slides_sources/source/session06.rst b/_sources/session07.txt similarity index 57% rename from slides_sources/source/session06.rst rename to _sources/session07.txt index c995604c..46bbd8e4 100644 --- a/slides_sources/source/session06.rst +++ b/_sources/session07.txt @@ -1,11 +1,19 @@ +.. include:: include.rst -.. Foundations 2: Python slides file, created by - hieroglyph-quickstart on Wed Apr 2 18:42:06 2014. +*************************** +Object Oriented Programming +*************************** + +Lightning Talks today +--------------------- -****************************************************************************************** -Session Six: Object oriented programming: Classes, instances, attributes, and subclassing -****************************************************************************************** +.. rst-class:: medium + | + | Charles E Robison + | + | Paul Vosper + | ================ Review/Questions @@ -14,53 +22,87 @@ Review/Questions Review of Previous Class ------------------------ -* Argument Passing: ``*args``, ``**kwargs`` +.. rst-class:: medium -* comprehensions + Advanced Argument passing -* ``lambda`` + Testing +Any questions? -Homework review ---------------- +Should I go over my solution(s)? -Homework Questions? -If it seems harder than it should be -- it is! +Notes from homework: +-------------------- -My Solution to the trigram: +**chaining or...** - * (``dict.setdefault()`` trick...) +Consider this: -``global`` keyword? +``elif selection == '3' or 'exit':`` -Unicode Notes -------------- +Careful here: you want to check if selection is '3' or 'exit', but that is no quite what this means: -To put unicode in your source file, put: +You want: -.. code-block:: python +``(selection == '3') or (selection == 'exit')`` + +== has higher precedence than or, so you don't need the parentheses. + +``selection == '3' or selection == 'exit'`` + +That feels like more typing, but that's what you have to do. + +.. nextslide:: - #!/usr/bin/env python - # -*- coding: utf-8 -*- +So what does the first version mean? -at the top of your file ... and be sure to save it as utf-8! -(file->save with encoding in Sublime) +It would return true for '3', but would never fail. Due to operator precedence, it is: -You also might want to put:: +``(selection == '3') or 'exit'`` - from __future__ import unicode_literals +so first it's checking if selection == '3', which will return True or False. +Then it does the or: ``True or 'exit'`` or ``False or 'exit'`` -Additional notes on using Unicode in Python see: +``or`` returns the first "truthy" value it finds, to it will return either True or 'exit', regardless of the value of selection. 'exit' is truthy, so this if clause will always run. - :ref:`unicode_supplement` +(let's try this out in iPython) =========================== Object Oriented Programming =========================== +.. rst-class:: medium centered + +.. container:: + + Classes + + Instances + + Class and instance attributes + + Subclassing + + Overriding methods + + + + +=========================== +Object Oriented Programming +=========================== + +A Core approach to organizing code. + +I'm going to go through this fast. + +So we can get to the actual coding. + + Object Oriented Programming --------------------------- @@ -105,18 +147,21 @@ Python is a Dynamic Language That clashes with "pure" OO Think in terms of what makes sense for your project - -- not any one paradigm of software design. + +-- not any one paradigm of software design. .. nextslide:: So what is "object oriented programming"? +| "Objects can be thought of as wrapping their data within a set of functions designed to ensure that the data are used appropriately, and to assist in that use" +| http://en.wikipedia.org/wiki/Object-oriented_programming @@ -198,36 +243,32 @@ method Python Classes ============== -Python Classes --------------- - -The ``class`` statement +.. rst-class:: left -``class`` creates a new type object: + The ``class`` statement -.. code-block:: ipython - - In [4]: class C(object): - pass - ...: - In [5]: type(C) - Out[5]: type + ``class`` creates a new type object: -A class is a type -- interesting! + .. code-block:: ipython -It is created when the statement is run -- much like ``def`` + In [4]: class C: + pass + ...: + In [5]: type(C) + Out[5]: type -You don't *have* to subclass from ``object``, but you *should* + A class is a type -- interesting! -(note on "new style" classes) + It is created when the statement is run -- much like ``def`` -.. nextslide:: +Python Classes +-------------- About the simplest class you can write .. code-block:: python - >>> class Point(object): + >>> class Point: ... x = 1 ... y = 2 >>> Point @@ -246,7 +287,7 @@ Basic Structure of a real class: .. code-block:: python - class Point(object): + class Point: # everything defined in here is in the class namespace def __init__(self, x, y): @@ -257,11 +298,11 @@ Basic Structure of a real class: p = Point(3,4) ## access the attributes - print "p.x is:", p.x - print "p.y is:", p.y + print("p.x is:", p.x) + print("p.y is:", p.y) -see: ``Examples/Session06/simple_class`` +see: ``Examples/Session07/simple_classes.py`` .. nextslide:: @@ -281,7 +322,7 @@ You can use it to do any set-up you need It gets the arguments passed when you call the class object: -.. code-block:: python +.. code-block:: python Point(x, y) @@ -296,7 +337,7 @@ The instance of the class is passed as the first parameter for every method. .. code-block:: python - class Point(object): + class Point: def a_function(self, x, y): ... @@ -306,8 +347,10 @@ Does this look familiar from C-style procedural programming? .. nextslide:: -Anything assigned to a ``self.`` attribute is kept in the instance -name space -- ``self`` *is* the instance. +Anything assigned to a ``self`` attribute is kept in the instance +name space + +-- ``self`` *is* the instance. That's where all the instance-specific data is. @@ -329,10 +372,9 @@ Note: the methods defined by ``def`` are class attributes as well. The class is one namespace, the instance is another. +.. code-block:: python -.. code-block:: python - - class Point(object): + class Point: size = 4 color= "red" ... @@ -349,9 +391,9 @@ class attributes are accessed with ``self`` also. Typical methods: -.. code-block:: python +.. code-block:: python - class Circle(object): + class Circle: color = "red" def __init__(self, diameter): @@ -369,7 +411,7 @@ They may or may not return something useful. Gotcha! -.. code-block:: python +.. code-block:: python ... def grow(self, factor=2): @@ -386,25 +428,40 @@ Huh???? I only gave 2 (demo of bound vs. unbound methods) -LAB / homework ---------------- +LAB +---- +.. rst-class:: medium -Let's say you need to render some html.. + We now know enough to do something useful. -The goal is to build a set of classes that render an html page. +Let's say you need to render some html... -``Examples/Session06/sample_html.html`` +The goal is to build a set of classes that render an html +page. -We'll start with a single class, then add some sub-classes to specialize the behavior +We'll start with a single class, then add some sub-classes +to specialize the behavior Details in: -:ref:`homework_html_renderer` +:ref:`exercise_html_renderer` +Let's get a start with step 1. in class. -Let's see if we can do step 1. in class... +I'll give you a few minutes to think about it -- then we'll get started as a group. +Lightning Talks +---------------- + +.. rst-class:: medium + + | + | Charles E Robisons + | + | Paul Vosper + | + ======================= Subclassing/Inheritance ======================= @@ -412,10 +469,11 @@ Subclassing/Inheritance Inheritance ----------- -In object-oriented programming (OOP), inheritance is a way to reuse code of existing objects, or to establish a subtype from an existing object. +In object-oriented programming (OOP), inheritance is a way to reuse code +of existing objects, or to establish a subtype from an existing object. - -Objects are defined by classes, classes can inherit attributes and behavior from pre-existing classes called base classes or super classes. +Objects are defined by classes, classes can inherit attributes and behavior +from pre-existing classes called base classes or super classes. The resulting classes are known as derived classes or subclasses. @@ -439,8 +497,6 @@ The simplest subclass in Python: ``A_subclass`` now has exactly the same behavior as ``The_superclass`` -NOTE: when we put ``object`` in there, it means we are deriving from object -- getting core functionality of all objects. - Overriding attributes --------------------- @@ -448,7 +504,7 @@ Overriding is as simple as creating a new attribute with the same name: .. code-block:: python - class Circle(object): + class Circle: color = "red" ... @@ -456,7 +512,7 @@ Overriding is as simple as creating a new attribute with the same name: class NewCircle(Circle): color = "blue" >>> nc = NewCircle - >>> print nc.color + >>> print(nc.color) blue @@ -469,7 +525,7 @@ Same thing, but with methods (remember, a method *is* an attribute in python) .. code-block:: python - class Circle(object): + class Circle: ... def grow(self, factor=2): """grows the circle's diameter by factor""" @@ -488,20 +544,20 @@ all the instances will have the new method .. nextslide:: Here's a program design suggestion: - whenever you override a method, the - interface of the new method should be the same as the old. It should take - the same parameters, return the same type, and obey the same preconditions - and postconditions. - If you obey this rule, you will find that any function - designed to work with an instance of a superclass, like a Deck, will also work - with instances of subclasses like a Hand or PokerHand. If you violate this - rule, your code will collapse like (sorry) a house of cards. +""" -[ThinkPython 18.10] +Whenever you override a method, the interface of the new method should be the same as the old. It should take the same parameters, return the same type, and obey the same preconditions and postconditions. +If you obey this rule, you will find that any function designed to work with an instance of a superclass, like a Deck, will also work with instances of subclasses like a Hand or PokerHand. If you violate this rule, your code will collapse like (sorry) a house of cards. + +""" + +| +| [ThinkPython 18.10] +| +| ( Demo of class vs. instance attributes ) -( Demo of class vs. instance attributes ) =================== More on Subclassing @@ -510,13 +566,13 @@ More on Subclassing Overriding \_\_init\_\_ ----------------------- -``__init__`` common method to override} +``__init__`` common method to override You often need to call the super class ``__init__`` as well .. code-block:: python - class Circle(object): + class Circle: color = "red" def __init__(self, diameter): self.diameter = diameter @@ -527,16 +583,15 @@ You often need to call the super class ``__init__`` as well Circle.__init__(self, diameter) - exception to: "don't change the method signature" rule. More subclassing ---------------- You can also call the superclass' other methods: -.. code-block:: python +.. code-block:: python - class Circle(object): + class Circle: ... def get_area(self, diameter): return math.pi * (diameter/2.0)**2 @@ -560,7 +615,7 @@ When to Subclass .. nextslide:: -"Is a" vs "Has a" +"**Is** a" vs "**Has** a"** You may have a class that needs to accumulate an arbitrary number of objects. @@ -582,7 +637,7 @@ Attribute resolution order When you access an attribute: -``An_Instance.something`` +``an_instance.something`` Python looks for it in this order: @@ -595,7 +650,7 @@ Python looks for it in this order: It can get more complicated... -http://www.python.org/getit/releases/2.3/mro/ +https://www.python.org/download/releases/2.3/mro/ http://python-history.blogspot.com/2010/06/method-resolution-order.html @@ -645,7 +700,7 @@ GvR: "Five Minute Multi- methods in Python": http://www.artima.com/weblogs/viewpost.jsp?thread=101605 -http://www.python.org/getit/releases/2.3/mro/ +https://www.python.org/download/releases/2.3/mro/ http://python-history.blogspot.com/2010/06/method-resolution-order.html @@ -683,21 +738,182 @@ http://pyvideo.org/video/880/stop-writing-classes -- you don't need a class" +=== +LAB +=== + +.. rst-class:: left medium + + * html renderer: let's see how much more we can do! + +.. rst-class:: left + + :ref:`exercise_html_renderer` + + Now we have a base class, and we can: + + * Subclass overriding class attributes + * Subclass overriding a method + * Subclass overriding the ``__init__`` + + These are the core OO approaches + + +=================== +More on Subclassing +=================== + +.. rst-class:: left + + This is a great talk (yes, I'm repeating): + + The Art of Subclassing: *Raymond Hettinger* + + http://pyvideo.org/video/879/the-art-of-subclassing + + If you haven't watched it, It's well worth your time + +What's a Subclass For? +---------------------- + +The most salient points from that video are as follows: + +* **Subclassing is not for Specialization** + +* **Subclassing is for Reusing Code** + +* **Bear in mind that the subclass is in charge** + + +Multiple Inheritance +-------------------- + +Multiple inheritance: Inheriting from more than one class + +Simply provide more than one parent. + +.. code-block:: python + + class Combined(Super1, Super2, Super3): + def __init__(self, something, something else): + # some custom initialization here. + Super1.__init__(self, ......) + Super2.__init__(self, ......) + Super3.__init__(self, ......) + # possibly more custom initialization + +(calls to the super class ``__init__`` are optional -- case dependent) + +.. nextslide:: Method Resolution Order + +.. code-block:: python + + class Combined(Super1, Super2, Super3) + +Attributes are located bottom-to-top, left-to-right + +* Is it an instance attribute ? +* Is it a class attribute ? +* Is it a superclass attribute ? + + - Is it an attribute of the left-most superclass? + - Is it an attribute of the next superclass? + - and so on up the hierarchy... + +* Is it a super-superclass attribute ? +* ... also left to right ... + +http://python-history.blogspot.com/2010/06/method-resolution-order.html + +.. nextslide:: Mix-ins + +So why would you want to do this? One reason: *mixins* + +Provides an subset of expected functionality in a re-usable package. + +Huh? this is why -- + +Hierarchies are not always simple: + +* Animal + + * Mammal + + * GiveBirth() + + * Bird + + * LayEggs() + +Where do you put a Platypus? + +Real World Example: `FloatCanvas`_ + +.. _FloatCanvas: https://github.com/wxWidgets/wxPython/blob/master/wx/lib/floatcanvas/FloatCanvas.py#L485 + + +``super()`` +----------- + +``super()``: use it to call a superclass method, rather than explicitly calling +the unbound method on the superclass. + +instead of: + +.. code-block:: python + + class A(B): + def __init__(self, *args, **kwargs) + B.__init__(self, *argw, **kwargs) + ... + +You can do: + +.. code-block:: python + + class A(B): + def __init__(self, *args, **kwargs) + super().__init__(*argw, **kwargs) + ... + +.. nextslide:: Caveats + +Caution: There are some subtle differences with multiple inheritance. + +You can use explicit calling to ensure that the 'right' method is called. + +.. rst-class:: medium + + **Background** + +Two seminal articles about ``super()``: + +"Super Considered Harmful" -- James Knight + +https://fuhm.net/super-harmful/ + +"super() considered super!" -- Raymond Hettinger + +http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ + +(Both worth reading....) + +======== Homework --------- +======== -Build an html rendering system: +Complete your html renderer. -:ref:`homework_html_renderer` +Watch these videos: -| +Python class toolkit: *Raymond Hettinger* -- https://youtu.be/HTLu2DFOdTg + +https://speakerdeck.com/pyconslides/pythons-class-development-toolkit-by-raymond-hettinger + +The Art of Subclassing: *Raymond Hettinger* -- http://pyvideo.org/video/879/the-art-of-subclassing -You will build an html generator, using: +Stop Writing Classes: *Jack Diederich* -- http://pyvideo.org/video/880/stop-writing-classes -* A Base Class with a couple methods -* Subclasses overriding class attributes -* Subclasses overriding a method -* Subclasses overriding the ``__init__`` +Read up on super() -These are the core OO approaches diff --git a/_sources/session08.txt b/_sources/session08.txt new file mode 100644 index 00000000..609a26e1 --- /dev/null +++ b/_sources/session08.txt @@ -0,0 +1,934 @@ +.. include:: include.rst + +**************************************************** +Session Eight: More OO: Properties, Special methods. +**************************************************** + + +================ +Review/Questions +================ + +Review of Previous Class +------------------------ + +* Basic OO Concepts + + * Classes + * class vs. instance attributes + * subclassing + * overriding methods / attributes + + +Lightning Talks Today: +----------------------- + +.. rst-class:: medium + + Paul Briant + + Jay Raina + + Josh Hicks + + +Personal Project +----------------- + +The bulk of the homework for the rest of the class will be a personal project: + +* It can be for fun, or something you need for your job. +* It should be large enough to take a few weeks homework time to do. +* **It should demostrate that you can do something useful with python.** +* It should follow PEP8 (https://www.python.org/dev/peps/pep-0008) +* It should have unit tests! +* Ideally, it will be in version control (gitHub) +* I don't require any specific python features (i.e. classes): use + what is appropriate for your project + +* Due the Sunday after the last class (December 11) + +| +| By next week, send me a project proposal: short and sweet. +| + +Homework review +--------------- + +* html renderer +* Test-driven development + +Homework Notes: +--------------- + +``**kwargs`` will always define a ``kwargs`` dict: it just may be empty. + +And there is no need to check if it's empty before trying to loop through it. + +.. code-block:: python + + if self.attributes != {}: + for key, value in self.attributes.items(): + self.atts += ' {}="{}"'.format(key, value) + +no need for ``!= {}`` -- an empty dict is "Falsey" + +**but** no need for that check at all. If the dict (or list, or tuple) is +empty, then the loop is a do-nothing operation: + +.. code-block:: python + + for key, value in self.attributes.items(): + self.atts += ' {}="{}"'.format(key, value) + +will not run if self.attributes is an empty dict. + + +Dynamic typing and class attributes +----------------------------------- + +* what happens if we change a class attribute after creating instances?? + + - let's try ``Element.indent`` ... + +* setting an instance attribute overwrites class attributes: + +``self.tag =`` overrights the class attribute (sort of!) + +Let's experiment with that. + + +dict as switch +-------------- + +.. rst-class:: medium + + What to use instead of "switch-case"? + +A number of languages have a "switch-case" construct:: + + switch(argument) { + case 0: + return "zero"; + case 1: + return "one"; + case 2: + return "two"; + default: + return "nothing"; + }; + +How do you spell this in python? + +``if-elif`` chains +------------------- + +The obvious way to spell it is a chain of ``elif`` statements: + +.. code-block:: python + + if argument == 0: + return "zero" + elif argument == 1: + return "one" + elif argument == 2: + return "two" + else: + return "nothing" + +And there is nothing wrong with that, but.... + +.. nextslide:: + +The ``elif`` chain is neither elegant nor efficient. + +There are a number of ways to spell it in python -- one elegant one is to use a dict: + +.. code-block:: python + + arg_dict = {0:"zero", 1:"one", 2: "two"} + dict.get(argument, "nothing") + +Simple, elegant, and fast. + +You can do a dispatch table by putting functions as the value. + +Example: Chris' mailroom2 solution. + +Polymorphism as switch: +----------------------- + +It turns out that a lot of uses of switch-case in non-OO languages is to +change behaviour depending on teh type of object being worked on:: + + switch(object.tag) { + case 'html': + render_html_element; + case 'p': + render_p_element; + ... + +I saw some of this in the html renderer: + +.. nextslide:: + +.. code-block:: python + + def render(out_file, ind=""): + .... + if self.tag == 'html': + tag = "" + end_tag = "" + elif self.tag == 'p': + tag = "

        " + end_tag = "

        " + +This will work, of course, but: + +* it means you need to know every tag that you might render when you write this render method. + +* In a more complex system, you will need to go update all sorts of things all over teh place when you add a tag. + +* It means anyone extending the system with more tags needs to edit the core base class. + +Polymorphism +------------ + +The alternative is to use polymorphism: + +Your ``render()`` method doesn't need to know what all the objects are +that it may need to render. + +All it needs to know is that they all will have a method +that does the right thing. + +So the above becomes, simply: + +.. code-block:: python + + def render(out_file, ind=""): + .... + tag, end_tag = self.make_tags() + +This is known as polymorphism, because many different objects are behave +the same way. + +.. nextslide:: + +This is usally handled by subclassing, so they all get all teh same +methods by default, and you only need to specialize the ones that need it. + +But in Python -- it can be done with duck-typing instead, as the TextWrapper example. + +Duck typing and EAFP +-------------------- + +* notes on Duck Typing: :ref:`exercise_html_renderer` + +* put the ``except`` as close as you can to where you expect an exception to be raised! + +* Let's look at a couple ways to do that. + +Code Review +----------- + +* anyone stuck that wants to work through your code? + +* And/or go through mine... + +Lightning Talks: +---------------- + +.. rst-class:: medium + + | + | Paul Briant + | + | Jay Raina + | + | Josh Hicks + + + +========== +Properties +========== + +.. rst-class:: left +.. container:: + + One of the strengths of Python is lack of clutter. + + Attributes are simple and concise: + + .. code-block:: ipython + + In [5]: class C: + def __init__(self): + self.x = 5 + In [6]: c = C() + In [7]: c.x + Out[7]: 5 + In [8]: c.x = 8 + In [9]: c.x + Out[9]: 8 + + +Getter and Setters? +------------------- + +But what if you need to add behavior later? + +.. rst-class:: build + +* do some calculation +* check data validity +* keep things in sync + + +.. nextslide:: + +.. code-block:: ipython + + In [5]: class C: + ...: def __init__(self): + ...: self.x = 5 + ...: def get_x(self): + ...: return self.x + ...: def set_x(self, x): + ...: self.x = x + ...: + In [6]: c = C() + In [7]: c.get_x() + Out[7]: 5 + In [8]: c.set_x(8) + In [9]: c.get_x() + Out[9]: 8 + + + This is ugly and verbose -- `Java`_? + +.. _Java: http://dirtsimple.org/2004/12/python-is-not-java.html + + +properties +----------- + +.. code-block:: ipython + + class C: + _x = None + @property + def x(self): + return self._x + @x.setter + def x(self, value): + self._x = value + + In [28]: c = C() + In [30]: c.x = 5 + In [31]: print(c.x) + 5 + +Now the interface is like simple attribute access! + +.. nextslide:: + +What's up with the "@" symbols? + +Those are "decorations" it's a syntax for wrapping functions up with something special. + +We'll cover that in detail in a couple weeks, but for now -- just copy the syntax. + +.. code-block:: python + + @property + def x(self): + +means: make a property called x with this as the "getter". + +.. code-block:: python + + @x.setter + def x(self, value): + +means: make the "setter" of the 'x' property this new function + +"Read Only" Attributes +---------------------- + +You do not need to define a setter. If you don't, you get a "read only" attribute: + +.. code-block:: ipython + + In [11]: class D(): + ....: def __init__(self, x=5): + ....: self._x = 5 + ....: @property + ....: def getx(self): + ....: """I am read only""" + ....: return self._x + ....: + In [12]: d = D() + In [13]: d.x + Out[13]: 5 + In [14]: d.x = 6 + --------------------------------------------------------------------------- + AttributeError Traceback (most recent call last) + in () + ----> 1 d.x = 6 + AttributeError: can't set attribute + +Deleters +--------- + +If you want to do something special when a property is deleted, you can define +a deleter is well: + +.. code-block:: ipython + + In [11]: class D(): + ....: def __init__(self, x=5): + ....: self._x = 5 + ....: @property + ....: def x(self): + ....: return self._x + ....: @x.deleter + ....: def x(self): + ....: del self._x + +If you leave this out, the property can't be deleted, which is usually +what you want. + +.. rst-class:: centered + +[demo: :download:`properties_example.py <../../Examples/Session08/properties_example.py>`] + + +=== +LAB +=== + +Let's use some of this to build a nice class to represent a Circle. + +For now, Let's do steps 1-4 of: + +:ref:`exercise_circle_class` + + +======================== +Static and Class Methods +======================== + +.. rst-class:: left build +.. container:: + + You've seen how methods of a class are *bound* to an instance when it is + created. + + And you've seen how the argument ``self`` is then automatically passed to + the method when it is called. + + And you've seen how you can call *unbound* methods on a class object so + long as you pass an instance of that class as the first argument. + + + .. rst-class:: centered + + **But what if you don't want or need an instance?** + + +Static Methods +-------------- + +A *static method* is a method that doesn't get self: + +.. code-block:: ipython + + In [36]: class StaticAdder: + + ....: @staticmethod + ....: def add(a, b): + ....: return a + b + ....: + + In [37]: StaticAdder.add(3, 6) + Out[37]: 9 + +.. rst-class:: centered + +[demo: :download:`static_method.py <../../Examples/Session08/static_method.py>`] + + +.. nextslide:: Why? + +.. rst-class:: build +.. container:: + + Where are static methods useful? + + Usually they aren't + + 99% of the time, it's better just to write a module-level function + + An example from the Standard Library (tarfile.py): + + .. code-block:: python + + class TarInfo: + # ... + @staticmethod + def _create_payload(payload): + """Return the string payload filled with zero bytes + up to the next 512 byte border. + """ + blocks, remainder = divmod(len(payload), BLOCKSIZE) + if remainder > 0: + payload += (BLOCKSIZE - remainder) * NUL + return payload + + +Class Methods +------------- + +A class method gets the class object, rather than an instance, as the first +argument + +.. code-block:: ipython + + In [41]: class Classy: + ....: x = 2 + ....: @classmethod + ....: def a_class_method(cls, y): + ....: print("in a class method: ", cls) + ....: return y ** cls.x + ....: + In [42]: Classy.a_class_method(4) + in a class method: + Out[42]: 16 + +.. rst-class:: centered + +[demo: :download:`class_method.py <../../Examples/Session08/class_method.py>`] + + +Why? +---- + +.. rst-class:: build +.. container:: + + Unlike static methods, class methods are quite common. + + They have the advantage of being friendly to subclassing. + + Consider this: + + .. code-block:: ipython + + In [44]: class SubClassy(Classy): + ....: x = 3 + ....: + + In [45]: SubClassy.a_class_method(4) + in a class method: + Out[45]: 64 + +Alternate Constructors +----------------------- + +Because of this friendliness to subclassing, class methods are often used to +build alternate constructors. + +Consider the case of wanting to build a dictionary with a given iterable of +keys: + +.. code-block:: ipython + + In [57]: d = dict([1,2,3]) + --------------------------------------------------------------------------- + TypeError Traceback (most recent call last) + in () + ----> 1 d = dict([1,2,3]) + + TypeError: cannot convert dictionary update sequence element #0 to a sequence + + +.. nextslide:: ``dict.fromkeys()`` + +The stock constructor for a dictionary won't work this way. So the dict object +implements an alternate constructor that *can*. + +.. code-block:: python + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S. + If not specified, the value defaults to None. + ''' + self = cls() + for key in iterable: + self[key] = value + return self + +(this is actually from the OrderedDict implementation in ``collections.py``) + +See also datetime.datetime.now(), etc.... + +.. nextslide:: Curious? + +Properties, Static Methods and Class Methods are powerful features of Python's +OO model. + +They are implemented using an underlying structure called *descriptors* + +`Here is a low level look`_ at how the descriptor protocol works. + +The cool part is that this mechanism is available to you, the programmer, as +well. + +.. _Here is a low level look: https://docs.python.org/2/howto/descriptor.html + + +For the Circle Lab: use a class method to make an alternate constructor that takes +the diameter instead. + +=============== +Special Methods +=============== + +.. rst-class:: left +.. container:: + + Special methods (also called *magic* methods) are the secret sauce to Python's Duck typing. + + Defining the appropriate special methods in your classes is how you make your class act like standard classes. + +What's in a Name? +----------------- + +We've seen at least one special method so far:: + + __init__ + +It's all in the double underscores... + +Pronounced "dunder" (or "under-under") + +try: ``dir(2)`` or ``dir(list)`` + +.. nextslide:: Generally Useful Special Methods + +Most classes should at least have these special methods: + +``object.__str__``: + Called by the str() built-in function and by the print function to compute + the *informal* string representation of an object. + +``object.__repr__``: + Called by the repr() built-in function to compute the *official* string representation of an object. + + (ideally: ``eval( repr(something) ) == something``) + +(demo) + +Protocols +---------- + +.. rst-class:: build +.. container:: + + The set of special methods needed to emulate a particular type of Python object is called a *protocol*. + + Your classes can "become" like Python built-in classes by implementing the + methods in a given protocol. + + Remember, these are more *guidelines* than laws. Implement what you need. + + +.. nextslide:: The Numerics Protocol + +Do you want your class to behave like a number? Implement these methods: + +.. code-block:: python + + object.__add__(self, other) + object.__sub__(self, other) + object.__mul__(self, other) + object.__floordiv__(self, other) + object.__mod__(self, other) + object.__divmod__(self, other) + object.__pow__(self, other[, modulo]) + object.__lshift__(self, other) + object.__rshift__(self, other) + object.__and__(self, other) + object.__xor__(self, other) + object.__or__(self, other) + +.. nextslide:: The Container Protocol + +Want to make a container type? Here's what you need: + +.. code-block:: python + + object.__len__(self) + object.__getitem__(self, key) + object.__setitem__(self, key, value) + object.__delitem__(self, key) + object.__iter__(self) + object.__reversed__(self) + object.__contains__(self, item) + object.__getslice__(self, i, j) + object.__setslice__(self, i, j, sequence) + object.__delslice__(self, i, j) + + +.. nextslide:: An Example + +Each of these methods supports a common Python operation. + +For example, to make '+' work with a sequence type in a vector-like fashion, +implement ``__add__``: + +.. code-block:: python + + def __add__(self, v): + """return the element-wise vector sum of self and v + """ + assert len(self) == len(v) + return vector([x1 + x2 for x1, x2 in zip(self, v)]) + +.. rst-class:: centered + +A more complete example may be seen in: + +Examples/Session08/vector.py + +or: :download:`here <../../Examples/Session08/vector.py>` + +.. nextslide:: Summary + +Use special methods when you want your class to act like a "standard" class in +some way. + +Look up the special methods you need and define them. + +There's more to read about the details of implementing these methods: + +* https://docs.python.org/3.5/reference/datamodel.html#special-method-names +* https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.markdown + +=== +LAB +=== + +Let's complete our nifty Circle class: + +Steps 5-8 of: + +:ref:`exercise_circle_class` + + +========================= +Emulating Standard types +========================= + +.. rst-class:: medium + + Making your classes behave like the built-ins + + +Callable classes +----------------- + +We've been using functions a lot: + +.. code-block:: python + + def my_fun(something): + do_something + ... + return something + +And then we can call it: + +.. code-block:: python + + result = my_fun(some_arguments) + +.. nextslide:: + +But what if we need to store some data to know how to evaluate that function? + +Example: a function that computes a quadratic function: + +.. math:: + + y = a x^2 + bx + c + +You could pass in a, b and c each time: + +.. code-block:: python + + def quadratic(x, a, b, c): + return a * x**2 + b * x + c + +But what if you are using the same a, b, and c numerous times? + +Or what if you need to pass this in to something +(like map) that requires a function that takes a single argument? + +"Callables" +----------- + +Various places in python expect a "callable" -- something that you can +call like a function: + +.. code-block:: python + + a_result = something(some_arguments) + +"something" in this case is often a function, but can be anything else +that is "callable". + +What have we been introduced to recently that is "callable", but not a +function object? + +Custom callable objects +------------------------ + +The trick is one of Python's "magic methods" + +.. code-block:: python + + __call__(*args, **kwargs) + +If you define a ``__call__`` method in your class, it will be used when +code "calls" an instance of your class: + +.. code-block:: python + + class Callable: + def __init__(self, .....) + some_initilization + def __call__(self, some_parameters) + +Then you can do: + +.. code-block:: python + + callable_instance = Callable(some_arguments) + + result = callable_instance(some_arguments) + + +Writing your own sequence type +------------------------------- + +Python has a handful of nifty sequence types built in: + + * lists + * tuples + * strings + * ... + +But what if you need a sequence that isn't built in? + +A Sparse array +-------------- + +Example: Sparse Array + +Sometimes we have data sets that are "sparse" -- i.e. most of the values are zero. + +So you may not want to store a huge bunch of zeros. + +But you do want the array to look like a regular old sequence. + +So how do you do that? + +The Sequence protocol +---------------------- + +You can make your class look like a regular python sequence by defining +the set of special methods you need: + +https://docs.python.org/3/reference/datamodel.html#emulating-container-types + +and + +https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.markdown#sequence + +The key ones are: + ++-------------------+-----------------------+ +| ``__len__`` | for ``len(sequence)`` | ++-------------------+-----------------------+ +| ``__getitem__`` | for ``x = seq[i]`` | ++-------------------+-----------------------+ +| ``__setitem__`` | for ``seq[i] = x`` | ++-------------------+-----------------------+ +| ``__delitem__`` | for ``del seq[i]`` | ++-------------------+-----------------------+ +| ``__contains__`` | for ``x in seq`` | ++-------------------+-----------------------+ + +==== +LAB +==== + +.. rst-class:: medium + + Let's do the previous motivating examples. + +Callables: +----------- + +Write a class for a quadratic equation. + +* The initializer for that class should take the parameters: ``a, b, c`` + +* It should store those parameters as attributes. + +* The resulting instance should evaluate the function when called, and return the result: + + +.. code-block:: python + + my_quad = Quadratic(a=2, b=3, c=1) + + my_quad(0) + +Sparse Array: +------------- + +Write a class for a sparse array: + +:ref:`exercise_sparse_array` + + +======== +Homework +======== + +.. rst-class:: left + + Reading: + + Lambda: + + http://www.blog.pythonlibrary.org/2015/10/28/python-101-lambda-basics/ + + https://pythonconquerstheuniverse.wordpress.com/2011/08/29/lambda_tutorial/ + + Complete the Circle class + + Complete the Sparse Array class + + Decide what you are going to do for your project, and send me a simple proposal. Get started if you can. + + Good book: + + Python 3 Object Oriented Programming: *Dusty Phillips* + + (Dusty is a local boy and co-founder of PuPPy) diff --git a/_sources/session09.txt b/_sources/session09.txt new file mode 100644 index 00000000..e6d953d7 --- /dev/null +++ b/_sources/session09.txt @@ -0,0 +1,656 @@ +.. include:: include.rst + +************************************************************ +Anonymous Functions and Iterators, Iterables, and Generators +************************************************************ + +==================== +Lightning Talks Now: +==================== + +.. rst-class:: medium + + Jack M Hefner + + Ninad Naik + + Simbarashe P Change + + +=================== +Anonymous functions +=================== + +lambda +------ + +.. code-block:: ipython + + In [171]: f = lambda x, y: x+y + In [172]: f(2,3) + Out[172]: 5 + +Content of function can only be an expression -- not a statement + +Anyone remember what the difference is? + +Called "Anonymous": it doesn't get a name. + +.. nextslide:: + +It's a python object, it can be stored in a list or other container + +.. code-block:: ipython + + In [7]: l = [lambda x, y: x+y] + In [8]: type(l[0]) + Out[8]: function + + +And you can call it: + +.. code-block:: ipython + + In [9]: l[0](3,4) + Out[9]: 7 + + +Functions as first class objects +--------------------------------- + +You can do that with "regular" functions too: + +.. code-block:: ipython + + In [12]: def fun(x,y): + ....: return x+y + ....: + In [13]: l = [fun] + In [14]: type(l[0]) + Out[14]: function + In [15]: l[0](3,4) + Out[15]: 7 + + + +====================== +Functional Programming +====================== + +No real consensus about what that means. + +But there are some "classic" methods available in Python. + +map +--- + +``map`` "maps" a function onto a sequence of objects -- It applies the function to each item in the list, returning another list + + +.. code-block:: ipython + + In [23]: l = [2, 5, 7, 12, 6, 4] + In [24]: def fun(x): + return x*2 + 10 + In [25]: map(fun, l) + Out[25]: + +Huh? what's a "map" object? It's an iterator (more on that later). + +.. code-block:: ipython + + In [19]: list(map(fun, l)) + Out[19]: [14, 20, 24, 34, 22, 18] + +Ah, that's better. + +But if it's a small function, and you only need it once: + +.. code-block:: ipython + + In [26]: list(map(lambda x: x*2 + 10, l)) + Out[26]: [14, 20, 24, 34, 22, 18] + + +filter +------ + +``filter`` "filters" a sequence of objects with a boolean function -- +It keeps only those for which the function is True -- filtering out the rest. + +To get only the even numbers: + +.. code-block:: ipython + + In [27]: l = [2, 5, 7, 12, 6, 4] + In [28]: list(filter(lambda x: not x%2, l)) + Out[28]: [2, 12, 6, 4] + +If you pass ``None`` to ``filter()``, you get only items that evaluate to true: + +.. code-block:: ipython + + In [1]: l = [1, 0, 2.3, 0.0, 'text', '', [1,2], [], False, True, None ] + + In [2]: list(filter(None, l)) + Out[2]: [1, 2.3, 'text', [1, 2], True] + + +Comprehensions +-------------- + +Couldn't you do all this with comprehensions? + +Yes: + +.. code-block:: ipython + + In [33]: [x+2 + 10 for x in l] + Out[33]: [14, 17, 19, 24, 18, 16] + + In [34]: [x for x in l if not x%2] + Out[34]: [2, 12, 6, 4] + + In [6]: l + Out[6]: [1, 0, 2.3, 0.0, 'text', '', [1, 2], [], False, True, None] + In [7]: [i for i in l if i] + Out[7]: [1, 2.3, 'text', [1, 2], True] + + +Functional Programming +---------------------- + +Comprehensions, map, and filter are all "functional programming" approaches + +``map, filter`` and ``reduce`` pre-date comprehensions in Python's history + +Some people like that syntax better + +And "map-reduce" is a big concept these days for parallel processing of "Big Data" in NoSQL databases. + +(Hadoop, MongoDB, etc.) + + +A bit more about lambda +------------------------ + +It is very useful for specifying the sorting key: + +.. code-block:: ipython + + In [55]: lst = [("Chris","Barker"), ("Fred", "Jones"), ("Zola", "Adams")] + + In [56]: lst.sort() + + In [57]: lst + Out[57]: [('Chris', 'Barker'), ('Fred', 'Jones'), ('Zola', 'Adams')] + + In [58]: lst.sort(key=lambda x: x[1]) + + In [59]: lst + Out[59]: [('Zola', 'Adams'), ('Chris', 'Barker'), ('Fred', 'Jones')] + +lambda and keyword arguments +---------------------------- + +.. code-block:: ipython + + In [186]: l = [] + In [187]: for i in range(3): + l.append(lambda x, e=i: x**e) + .....: + In [189]: for f in l: + print(f(3)) + 1 + 3 + 9 + +Note when the keyword argument is evaluated: this turns out to be very handy! + +=== +LAB +=== + +Here's an exercise to try out some of this: + +:ref:`exercise_lambda_magic` + + + +=== +LAB +=== + +Let's use some of this ability to use functions a objects for something useful: + +:ref:`exercise_trapezoidal_rule` + + +========================= +Iterators and Generators +========================= + + +.. rst-class:: large centered + + The Tools of Pythonicity + + +.. rst-class:: medium + + What goes on in those for loops? + +Iterators and Iterables +----------------------- + +Iteration is one of the main reasons Python code is so readable: + +.. code-block:: python + + for x in just_about_anything: + do_stuff(x) + +An iterable is anything that can be looped over sequentially, so it does not have to be +a "sequence": list, tuple, etc. For example, a string is iterable. + +An iterator is an iterable that remembers state. All sequences are iterable, but +not all sequences are iterators. To make a sequence an iterator, you can call it with iter: + +.. code-block:: python + + my_iter = iter(my_sequence) + +Iterator Types: + +https://docs.python.org/3/library/stdtypes.html#iterator-types + +Iterables +--------- + +To make an object iterable, you simply have to implement the __getitem__ method. + +.. code-block:: python + + class T: + def __getitem__(self, position): + if position > 5: + raise IndexError + return position + +Demo + + +``iter()`` +----------- + +How do you get the iterator object from an "iterable"? + +The iter function will make any iterable an iterator. It first looks for the __iter__ +method, and if none is found, uses get_item to create the iterator. + +The ``iter()`` function: + +.. code-block:: ipython + + In [20]: iter([2,3,4]) + Out[20]: + + In [21]: iter("a string") + Out[21]: + + In [22]: iter( ('a', 'tuple') ) + Out[22]: + + +List as an Iterator: +-------------------- + +.. code-block:: ipython + + In [10]: a_list = [1,2,3] + + In [11]: list_iter = iter(a_list) + + In [12]: next(list_iter) + Out[12]: 1 + + In [13]: next(list_iter) + Out[13]: 2 + + In [14]: next(list_iter) + Out[14]: 3 + + In [15]: next(list_iter) + -------------------------------------------------- + StopIteration Traceback (most recent call last) + in () + ----> 1 next(list_iter) + StopIteration: + +Using iterators when you can +---------------------------- + +Example: trigrams: + +.. code-block:: ipython + + triplets = zip(words, words[1:], words[2:]) + +zip() returns an iterable -- it does not build up the whole list. +So this is quite efficient. + +but slicing: ([1:]) produces a copy -- so this does use three copies of +the list -- not so good if memory is tight. Note that they are shallow copies, so not **that** bad. + +Nevertheless, we can do better: + +.. code-block:: ipython + + from itertools import islice + + In [68]: triplets = zip(words, islice(words, 1, None), islice(words, 2, None)) + + In [69]: for triplet in triplets: + ...: print(triplet) + ...: + ('this', 'that', 'the') + ('that', 'the', 'other') + ('the', 'other', 'and') + ('other', 'and', 'one') + ('and', 'one', 'more') + + +The Iterator Protocol +---------------------- + +The main thing that differentiates an iterator from an iterable (sequence) +is that an iterator saves state. + +An iterable must have the following methods: + +.. code-block:: python + + an_iterator.__iter__() + +Usually returns the iterator object itself. + +.. code-block:: python + + an_iterator.__next__() + +Returns the next item from the container. If there are no further items, +raises the ``StopIteration`` exception. + + +Making an Iterator +------------------- + +A simple version of ``range()`` + +.. code-block:: python + + class IterateMe_1: + def __init__(self, stop=5): + self.current = 0 + self.stop = stop + def __iter__(self): + return self + def __next__(self): + if self.current < self.stop: + self.current += 1 + return self.current + else: + raise StopIteration + +(demo: :download:`iterator_1.py <../../Examples/Session09/iterator_1.py>`) + +What does ``for`` do? +---------------------- + +Now that we know the iterator protocol, we can write something like a for loop: + + +:download:`my_for.py <../../Examples/Session09/my_for.py>` + +.. code-block:: python + + def my_for(an_iterable, func): + """ + Emulation of a for loop. + + func() will be called with each item in an_iterable + """ + # equiv of "for i in l:" + iterator = iter(an_iterable) + while True: + try: + i = next(iterator) + except StopIteration: + break + func(i) + + +Itertools +--------- + +``itertools`` is a collection of utilities that make it easy to +build an iterator that iterates over sequences in various common ways + +http://docs.python.org/3/library/itertools.html + +NOTE: + +iteratables are not *only* for ``for`` + +They can be used with anything that expects an iterable: + +``sum``, ``tuple``, ``sorted``, and ``list`` + + +LAB +----- + +In the ``Examples/session09`` dir, you will find: +:download:`iterator_1.py <../../Examples/Session09/iterator_1.py>` + +* Extend (``iterator_1.py`` ) to be more like ``range()`` -- add three input parameters: ``iterator_2(start, stop, step=1)`` + +* What happens if you break from a loop and try to pick it up again: + +.. code-block:: python + + it = IterateMe_2(2, 20, 2) + for i in it: + if i > 10: break + print(i) + +.. code-block:: python + + for i in it: + print(i) + +* Does ``range()`` behave the same? + + - make yours match ``range()`` + + - is range an iterator or an iteratable? + + + +Generators +---------- + +Generators + +* give you an iterator object +* no access to the underlying data ... if it even exists + + +Conceptually: + Iterators are about various ways to loop over data. + + Generators can generate the data on the fly. + +Practically: + You can use either one either way (and a generator is one type of iterator). + + Generators do some of the book-keeping for you -- simpler syntax. + +yield +------ + +``yield`` is a way to make a quickie generator with a function: + +.. code-block:: python + + def a_generator_function(params): + some_stuff + yield something + +Generator functions "yield" a value, rather than returning a value. + +State is preserved in between yields. + + +.. nextslide:: generator functions + +A function with ``yield`` in it is a "factory" for a generator + +Each time you call it, you get a new generator: + +.. code-block:: python + + gen_a = a_generator() + gen_b = a_generator() + +Each instance keeps its own state. + +Really just a shorthand for an iterator class that does the book keeping for you. + +.. nextslide:: + +An example: like ``range()`` + +.. code-block:: python + + def y_range(start, stop, step=1): + i = start + while i < stop: + yield i + i += step + +Real World Example from FloatCanvas: + +https://github.com/svn2github/wxPython/blob/master/3rdParty/FloatCanvas/floatcanvas/FloatCanvas.py#L100 + + +.. nextslide:: + +Note: + +.. code-block:: ipython + + In [164]: gen = y_range(2,6) + In [165]: type(gen) + Out[165]: generator + In [166]: dir(gen) + Out[166]: + ... + '__iter__', + ... + '__next__', + + +So the generator **is** an iterator + +Note: A generator function can also be a method in a class + + +More about iterators and generators: + +http://www.learningpython.com/2009/02/23/iterators-iterables-and-generators-oh-my/ + +:download:`yield_example.py <../../Examples/Session09/yield_example.py>` + +generator comprehension +----------------------- + +yet another way to make a generator: + +.. code-block:: python + + >>> [x * 2 for x in [1, 2, 3]] + [2, 4, 6] + >>> (x * 2 for x in [1, 2, 3]) + at 0x10911bf50> + >>> for n in (x * 2 for x in [1, 2, 3]): + ... print n + ... 2 4 6 + + +More interesting if [1, 2, 3] is also a generator + +Note that `map` and `filter` produce iterators. + +LAB +---- + +Write a few generators: + +* Sum of integers +* Doubler +* Fibonacci sequence +* Prime numbers + +(test code in +:download:`test_generator.py <../../Examples/Session09/test_generator.py>`) + +Descriptions: + +Sum of the integers: + keep adding the next integer + + 0 + 1 + 2 + 3 + 4 + 5 + ... + + so the sequence is: + + 0, 1, 3, 6, 10, 15 ..... + +.. nextslide:: + +Doubler: + Each value is double the previous value: + + 1, 2, 4, 8, 16, 32, + +Fibonacci sequence: + The fibonacci sequence as a generator: + + f(n) = f(n-1) + f(n-2) + + 1, 1, 2, 3, 5, 8, 13, 21, 34... + +Prime numbers: + Generate the prime numbers (numbers only divisible by them self and 1): + + 2, 3, 5, 7, 11, 13, 17, 19, 23... + +Others to try: + Try x^2, x^3, counting by threes, x^e, counting by minus seven, ... + + +========== +Next Week +========== + +Decorators and Context managers -- fun stuff! + + +Homework +--------- + +Finish up the labs + +Work on your project -- not much time left! + +And *do* let me know what you're doing if you haven't yet! diff --git a/slides_sources/source/session08.rst b/_sources/session10.txt similarity index 55% rename from slides_sources/source/session08.rst rename to _sources/session10.txt index c3152d53..8465c79e 100644 --- a/slides_sources/source/session08.rst +++ b/_sources/session10.txt @@ -1,46 +1,86 @@ -********************************************************************** -Session Eight: Generators, Iterators, Decorators, and Context Managers -********************************************************************** - -.. rst-class:: large centered - -The tools of Pythonicity +.. include:: include.rst +******************************************************* +Session Ten: Decorators and Context Managers -- Wrap Up +******************************************************* +================ Review/Questions ================ Review of Previous Class ------------------------ -* Advanced OO Concepts +Any questions??? - * Properties - * Special Methods +Homework review +--------------- -* Testing with pytest +Homework Questions? +From any of the Exercises... -Homework review ---------------- -* Circle Class -* Writing Tests using the ``pytest`` module +Projects +-------- + +Due Sunday, Dec 11th + +.. rst-class:: medium + + (that's five days!) + +Push to github or email them to me. + +====================== +Lightning Talks Today: +====================== + +.. rst-class:: medium + + Marcus D Williams + + Minghao Yang + + Sasi Mandava + +============ +Code Review? +============ + + + +.. rst-class:: left + + Anyone unsatisfied with their solution -- or stuck? + + Do you think you've "got" iterators, iterables, and generators? + + Options: + + 1) Look at someone's code. + + 2) look at some of my code. + + 3) Go over someone's project code -- anyone stuck on something? + + 4) wait till the end of class -- and see how much time we have. + +========== Decorators ========== -**A Short Digression** +**A Short Reminder** -.. rst-class:: left build -.. container:: +.. rst-class:: left Functions are things that generate values based on input (arguments). In Python, functions are first-class objects. - This means that you can bind symbols to them, pass them around, just like + This means that you can bind names to them, pass them around, etc., just like other objects. Because of this fact, you can write functions that take functions as @@ -53,21 +93,21 @@ Decorators return "I'm not that other function" return new_function + A Definition ------------ -There are many things you can do with a simple pattern like this one. So many, -that we give it a special name: +There are many things you can do with a simple pattern like this one. +So many, that we give it a special name: -.. rst-class:: centered +.. rst-class:: centered medium **Decorator** -.. rst-class:: build -.. container:: +.. rst-class:: build centered - A decorator is a function that takes a function as an argument and - returns a function as a return value. + "A decorator is a function that takes a function as an argument and + returns a function as a return value." That's nice and all, but why is that useful? @@ -85,21 +125,21 @@ one: .. rst-class:: build .. container:: - You want to see when each function is called, with what arguments and with what - result. So you rewrite each function as follows: + You want to see when each function is called, with what arguments and + with what result. So you rewrite each function as follows: .. code-block:: python def add(a, b): - print "Function 'add' called with args: %r" % locals() + print("Function 'add' called with args: {}, {}".format(a, b) ) result = a + b - print "\tResult --> %r" % result + print("\tResult --> {}".format(result)) return result .. nextslide:: -That's not particularly nice, especially if you have lots of functions in your -module. +That's not particularly nice, especially if you have lots of functions +in your module. Now imagine we defined the following, more generic *decorator*: @@ -107,16 +147,18 @@ Now imagine we defined the following, more generic *decorator*: def logged_func(func): def logged(*args, **kwargs): - print "Function %r called" % func.__name__ + print("Function {} called".format(func.__name__)) if args: - print "\twith args: %r" % args + print("\twith args: {}".format(args)) if kwargs: - print "\twith kwargs: %r" % kwargs + print("\twith kwargs: {}".format(kwargs)) result = func(*args, **kwargs) - print "\t Result --> %r" % result + print("\t Result --> {}".format(result)) return result return logged +(demo) + .. nextslide:: We could then make logging versions of our module functions: @@ -178,25 +220,24 @@ Rebinding the name of a function to the result of calling a decorator on that function is called **decoration**. Because this is so common, Python provides a special operator to perform it -more *declaratively*: the ``@`` operator: +more *declaratively*: the ``@`` operator +-- I told you I'd eventually explain what was going on under the hood with +that wierd `@` symbol: .. code-block:: python - # this is the imperative version: def add(a, b): return a + b add = logged_func(add) - # and this declarative form is exactly equal: @logged_func def add(a, b): return a + b -.. rst-class:: build -.. container:: +The declarative form (called a decorator expression) is far more common, +but both have the identical result, and can be used interchangeably. - The declarative form (called a decorator expression) is far more common, - but both have the identical result, and can be used interchangeably. +(demo) Callables --------- @@ -206,12 +247,12 @@ incomplete. In reality, decorators can be used with anything that is *callable*. -In python a *callable* is a function, a method on a class, or even a class that -implements the ``__call__`` special method. +Remember from last week, a *callable* is a function, a method on a class, +or a class that implements the ``__call__`` special method. So in fact the definition should be updated as follows: -.. rst-class:: centered +.. rst-class:: centered medium A decorator is a callable that takes a callable as an argument and returns a callable as a return value. @@ -257,14 +298,14 @@ Let's try that out with a potentially expensive function: In [58]: sum2x(10000000) Out[58]: 99999990000000 -It's nice to see that in action, but what if we want to know *exactly* how much -difference it made? +It's nice to see that in action, but what if we want to know *exactly* +how much difference it made? Nested Decorators ----------------- -You can stack decorator expressions. The result is like calling each decorator -in order, from bottom to top: +You can stack decorator expressions. The result is like calling each +decorator in order, from bottom to top: .. code-block:: python @@ -290,7 +331,7 @@ Let's define another decorator that will time how long a given call takes: start = time.time() result = func(*args, **kwargs) elapsed = time.time() - start - print "time expired: %s" % elapsed + print("time expired: {}".format(elapsed)) return result return timed @@ -312,30 +353,40 @@ decorator: time expired: 4.05311584473e-06 Out[73]: 99999990000000 + Examples from the Standard Library ---------------------------------- It's going to be a lot more common for you to use pre-defined decorators than for you to be writing your own. -Let's see a few that might help you with work you've been doing recently. +We've seen a few already: + +.. nextslide:: -For example, a ``staticmethod()`` can be implemented with a decorator -expression: +For example, ``@staticmethod`` and ``@classmethod`` can also be used as simple +callables, without the nifty decorator expression: .. code-block:: python # the way we saw last week: class C(object): + @staticmethod def add(a, b): return a + b - add = staticmethod(add) - # and the decorator form +Is exactly the same as: + +.. code-block:: python + class C(object): - @staticmethod def add(a, b): return a + b + add = staticmethod(add) + +Note that the "``def``" binds the name ``add``, then the next line +rebinds it. + .. nextslide:: @@ -343,41 +394,27 @@ The ``classmethod()`` builtin can do the same thing: .. code-block:: python - # in imperative style: + # in declarative style class C(object): + @classmethod def from_iterable(cls, seq): # method body - from_iterable = classmethod(from_iterable) - # and in declarative style + # in imperative style: class C(object): - @classmethod def from_iterable(cls, seq): # method body + from_iterable = classmethod(from_iterable) -.. nextslide:: - -Perhaps most commonly, you'll see the ``property()`` builtin used this way. - -Last week we saw this code: -.. code-block:: python +property() +----------- - class C(object): - def __init__(self): - self._x = None - def getx(self): - return self._x - def setx(self, value): - self._x = value - def delx(self): - del self._x - x = property(getx, setx, delx, - "I'm the 'x' property.") +Remember the property() built in? -.. nextslide:: +Perhaps most commonly, you'll see the ``property()`` builtin used this way. -Used in a decorator statement, it looks like this: +Two weeks ago we saw this code: .. code-block:: python @@ -394,357 +431,102 @@ Used in a decorator statement, it looks like this: def x(self): del self._x -Note that in this case, the decorator object returned by the property decorator -itself implements additional decorators as attributes on the returned method -object. - -Iterators and Generators -========================= - -Iterators ---------- -Iterators are one of the main reasons Python code is so readable: - -.. code-block:: python - - for x in just_about_anything: - do_stuff(x) - -It does not have to be a "sequence": list, tuple, etc. - -Rather: you can loop through anything that satisfies the "iterator protocol" - -http://docs.python.org/library/stdtypes.html#iterator-types - -The Iterator Protocol ----------------------- - -An iterator must have the following methods: - -.. code-block:: python - - an_iterator.__iter__() - -Returns the iterator object itself. This is required to allow both containers -and iterators to be used with the ``for`` and ``in`` statements. - -.. code-block:: python - - an_iterator.next() - -Returns the next item from the container. If there are no further items, -raises the ``StopIteration`` exception. - -List as an Iterator: --------------------- - -.. code-block:: ipython - - In [10]: a_list = [1,2,3] - - In [11]: list_iter = a_list.__iter__() - - In [12]: list_iter.next() - Out[12]: 1 - - In [13]: list_iter.next() - Out[13]: 2 - - In [14]: list_iter.next() - Out[14]: 3 - - In [15]: list_iter.next() - -------------------------------------------------- - StopIteration Traceback (most recent call last) - in () - ----> 1 list_iter.next() - StopIteration: - -Making an Iterator -------------------- - -A simple version of ``xrange()`` - -.. code-block:: python - - class IterateMe_1(object): - def __init__(self, stop=5): - self.current = 0 - self.stop = stop - def __iter__(self): - return self - def next(self): - if self.current < self.stop: - self.current += 1 - return self.current - else: - raise StopIteration - -(demo: ``code/iterator_1.py``) - -``iter()`` ------------ - -How doyou get the iterator object (the thing with the next() method) from an "iterable"? - -The ``iter()`` function: - -.. code-block:: ipython - - In [20]: iter([2,3,4]) - Out[20]: - - In [21]: iter("a string") - Out[21]: - - In [22]: iter( ('a', 'tuple') ) - Out[22]: - -for an arbitrary object, ``iter()`` calls the ``__iter__`` method. But it knows about some object (``str``, for instance) that don't have a ``__iter__`` method. - - -What does ``for`` do? ----------------------- - -Now that we know the iterator protocol, we can write something like a for loop: - -(``code/session08/my_for.py``) - -.. code-block:: python - - def my_for(an_iterable, func): - """ - Emulation of a for loop. - - func() will be called with each item in an_iterable - """ - # equiv of "for i in l:" - iterator = iter(an_iterable) - while True: - try: - i = iterator.next() - except StopIteration: - break - func(i) - - -Itertools ---------- - -``itertools`` is a collection of utilities that make it easy to -build an iterator that iterates over sequences in various common ways - -http://docs.python.org/library/itertools.html - -NOTE: - -iterators are not *only* for ``for`` - -They can be used with anything that expexts an iterator: - -``sum``, ``tuple``, ``sorted``, and ``list`` - -For example. - -LAB / Homework --------------- - -In the ``code/session08`` dir, you will find: ``iterator_1.py`` - -* Extend (``iterator_1.py`` ) to be more like ``xrange()`` -- add three input parameters: ``iterator_2(start, stop, step=1)`` - -* See what happens if you break out in the middle of the loop: - -.. code-block:: python - - it = IterateMe_2(2, 20, 2) - for i in it: - if i > 10: break - print i - -And then pick up again: - -.. code-block:: python - - for i in it: - print i - -* Does ``xrange()`` behave the same? - - - make yours match ``xrange()`` - -Generators ----------- - -Generators give you the iterator immediately: - -* no access to the underlying data ... if it even exists - - -Conceptually: - Iterators are about various ways to loop over data, generators generate the data on the fly - -Practically: - You can use either either way (and a generator is one type of iterator - - Generators do some of the book-keeping for you. - -yield ------ - -``yield`` is a way to make a quickie generator with a function: - -.. code-block:: python - - def a_generator_function(params): - some_stuff - yield something - -Generator functions "yield" a value, rather than returning a value. - -State is preserved in between yields. - - .. nextslide:: -A function with ``yield`` in it is a "factory" for a generator - -Each time you call it, you get a new generator: +But this could also be accomplished like so: .. code-block:: python - gen_a = a_generator() - gen_b = a_generator() - -Each instance keeps its own state. - -Really just a shorthand for an iterator class that does the book keeping for you. - -.. nextslide:: - -An example: like ``xrange()`` - -.. code-block:: python - - def y_xrange(start, stop, step=1): - i = start - while i < stop: - yield i - i += step - -Real World Example from FloatCanvas: - -https://github.com/svn2github/wxPython/blob/master/3rdParty/FloatCanvas/floatcanvas/FloatCanvas.py#L100 - - -.. nextslide:: - -Note: - -.. code-block:: ipython + class C(object): + def __init__(self): + self._x = None + def getx(self): + return self._x + def setx(self, value): + self._x = value + def delx(self): + del self._x + x = property(getx, setx, delx, + "I'm the 'x' property.") - In [164]: gen = y_xrange(2,6) - In [165]: type(gen) - Out[165]: generator - In [166]: dir(gen) - Out[166]: - ... - '__iter__', - ... - 'next', +``Examples/Session10/property_ugly.py`` -So the generator **is** an iterator .. nextslide:: -A generator function can also be a method in a class - - -More about iterators and generators: - -http://www.learningpython.com/2009/02/23/iterators-iterables-and-generators-oh-my/ - -``code/session08/yield_example.py`` - - -generator comprehension ------------------------ +Note that in this case, the decorator object returned by the property decorator +itself implements additional decorators as attributes on the returned method +object. So you could actually do this: -yet another way to make a generator: .. code-block:: python - >>> [x * 2 for x in [1, 2, 3]] - [2, 4, 6] - >>> (x * 2 for x in [1, 2, 3]) - at 0x10911bf50> - >>> for n in (x * 2 for x in [1, 2, 3]): - ... print n - ... 2 4 6 - - -More interesting if [1, 2, 3] is also a generator - -Generator LAB / Homework -------------------------- - - -Write a few generators: - -* Sum of integers -* Doubler -* Fibonacci sequence -* Prime numbers - -(test code in ``code/session08/test_generator.py``) - -Descriptions: + class C(object): + def __init__(self): + self._x = None + def x(self): + return self._x + x = property(x) + def _set_x(self, value): + self._x = value + x = x.setter(_set_x) + def _del_x(self): + del self._x + x = x.deleter(_del_x) -Sum of the integers: - keep adding the next integer +But that's getting really ugly! - 0 + 1 + 2 + 3 + 4 + 5 + ... +LAB +---- - so the sequence is: +**p_wrapper Decorator** - 0, 1, 3, 6, 10, 15 ..... +Write a simple decorator you can apply to a function that returns a string. -.. nextslide:: +Decorating such a function should result in the original output, wrapped by an +HTML 'p' tag: -Doubler: - Each value is double the previous value: +.. code-block:: ipython - 1, 2, 4, 8, 16, 32, + In [4]: @p_wrapper + ...: def return_a_string(string): + ...: return string + ...: -Fibonacci sequence: - The fibonacci sequence as a generator: + In [5]: return_a_string("this is a string") + Out[5]: '

        this is a string

        ' - f(n) = f(n-1) + f(n-2) +simple test code in: - 1, 1, 2, 3, 5, 8, 13, 21, 34... +``Examples/Session10/test_p_wrapper.py`` -Prime numbers: - Generate the prime numbers (numbers only divisible by them self and 1): - 2, 3, 5, 7, 11, 13, 17, 19, 23... +Lightning Talks +---------------- -Others to try: - Try x^2, x^3, counting by threes, x^e, counting by minus seven, ... +.. rst-class:: medium +| +| Marcus D Williams +| +| Minghao Yang +| +| Sasi Mandava +| +================= Context Managers -================ +================= -**A Short Digression** +**Repetition in code stinks (DRY!)** .. rst-class:: left build .. container:: - Repetition in code stinks. - A large source of repetition in code deals with the handling of externals + A large source of repetition in code deals with the handling of external resources. As an example, how many times do you think you might type the following @@ -761,6 +543,7 @@ Context Managers What happens if reading the file raises an exception? + Resource Handling ----------------- @@ -779,7 +562,7 @@ You can write more robust code for handling your resources: # do something with file_content here But what exceptions do you want to catch? And do you really want to have to -remember all that **every** time you open a resource? +remember to type all that **every** time you open a resource? .. nextslide:: It Gets Better @@ -795,7 +578,8 @@ few simple steps. The key is to use the ``with`` statement. -.. nextslide:: ``with`` a little help +``with`` a little help +---------------------- Since the introduction of the ``with`` statement in `pep343`_, the above six lines of defensive code have been replaced with this simple form: @@ -808,7 +592,7 @@ lines of defensive code have been replaced with this simple form: ``open`` builtin is defined as a *context manager*. -The resource it returnes (``file_handle``) is automatically and reliably closed +The resource it returns (``file_handle``) is automatically and reliably closed when the code block ends. .. _pep343: http://legacy.python.org/dev/peps/pep-0343/ @@ -818,18 +602,17 @@ when the code block ends. At this point in Python history, many functions you might expect to behave this way do: -.. rst-class:: build - -* ``open`` and ``codecs.open`` both work as context managers +* ``open`` and works as a context manager. * networks connections via ``socket`` do as well. * most implementations of database wrappers can open connections or cursors as context managers. * ... -But what if you are working with a library that doesn't support this -(``urllib``)? +* But what if you are working with a library that doesn't support this + (``urllib``)? -.. nextslide:: Close It Automatically +Close It Automatically +---------------------- There are a couple of ways you can go. @@ -838,32 +621,35 @@ the ``closing`` context manager from ``contextlib`` to handle the issue: .. code-block:: python - import urllib + from urllib import request from contextlib import closing - with closing(urllib.urlopen('http://google.com')) as web_connection: + with closing(request.urlopen('http://google.com')) as web_connection: # do something with the open resource # and here, it will be closed automatically -But what if the thing doesn't have a ``close()`` method, or you're creating the thing and it shouldn't? +But what if the thing doesn't have a ``close()`` method, or you're creating +the thing and it shouldn't have a close() method? -.. nextslide:: Do It Yourself +(full confession: urlib.request was not a context manager in py2 -- but it is in py3) + +Do It Yourself +-------------- You can also define a context manager of your own. -The interface is simple. It must be a class that implements these two *special -methods*: +The interface is simple. It must be a class that implements two +more of the nifty python *special methods* -``__enter__(self)``: - Called when the ``with`` statement is run, it should return something to work - with in the created context. +**__enter__(self)** Called when the ``with`` statement is run, it should +return something to work with in the created context. -``__exit__(self, e_type, e_val, e_traceback)``: - Clean-up that needs to happen is implemented here. +**__exit__(self, e_type, e_val, e_traceback)** Clean-up that needs to +happen is implemented here. - The arguments will be the exception raised in the context. +The arguments will be the exception raised in the context. - If the exception will be handled here, return True. If not, return False. +If the exception will be handled here, return True. If not, return False. Let's see this in action to get a sense of what happens. @@ -875,28 +661,33 @@ Consider this code: .. code-block:: python class Context(object): - """from Doug Hellmann, PyMOTW - http://pymotw.com/2/contextlib/#module-contextlib - """ - def __init__(self, handle_error): - print '__init__(%s)' % handle_error - self.handle_error = handle_error - def __enter__(self): - print '__enter__()' - return self - def __exit__(self, exc_type, exc_val, exc_tb): - print '__exit__(%s, %s, %s)' % (exc_type, exc_val, exc_tb) - return self.handle_error + """from Doug Hellmann, PyMOTW + https://pymotw.com/3/contextlib/#module-contextlib + """ + def __init__(self, handle_error): + print('__init__({})'.format(handle_error)) + self.handle_error = handle_error + + def __enter__(self): + print('__enter__()') + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + print('__exit__({}, {}, {})'.format(exc_type, exc_val, exc_tb)) + return self.handle_error + +``Examples/Session10/context_managers.py`` + .. nextslide:: -This class doesn't do much of anything, but playing with it can help clarify -the order in which things happen: +This class doesn't do much of anything, but playing with it can help +clarify the order in which things happen: .. code-block:: ipython In [46]: with Context(True) as foo: - ....: print 'This is in the context' + ....: print('This is in the context') ....: raise RuntimeError('this is the error message') __init__(True) __enter__() @@ -915,7 +706,7 @@ What if we try with ``False``? .. code-block:: ipython In [47]: with Context(False) as foo: - ....: print 'This is in the context' + ....: print('This is in the context') ....: raise RuntimeError('this is the error message') __init__(False) __enter__() @@ -930,9 +721,10 @@ What if we try with ``False``? 4 RuntimeError: this is the error message -.. nextslide:: ``contextmanager`` decorator +The ``contextmanager`` decorator +-------------------------------- -``contextlib.contextmanager`` turns generator functions into context managers +``contextlib.contextmanager`` turns generator functions into context managers. Consider this code: @@ -942,16 +734,16 @@ Consider this code: @contextmanager def context(boolean): - print "__init__ code here" + print("__init__ code here") try: - print "__enter__ code goes here" + print("__enter__ code goes here") yield object() except Exception as e: - print "errors handled here" + print("errors handled here") if not boolean: - raise + raise e finally: - print "__exit__ cleanup goes here" + print("__exit__ cleanup goes here") .. nextslide:: @@ -961,9 +753,10 @@ And using it has similar results. We can handle errors: .. code-block:: ipython - In [50]: with context(True): - ....: print "in the context" + In [96]: with context(True): + ....: print("in the context") ....: raise RuntimeError("error raised") + ....: __init__ code here __enter__ code goes here in the context @@ -977,7 +770,7 @@ Or, we can allow them to propagate: .. code-block:: ipython In [51]: with context(False): - ....: print "in the context" + ....: print("in the context") ....: raise RuntimeError("error raised") __init__ code here __enter__ code goes here @@ -993,18 +786,12 @@ Or, we can allow them to propagate: 4 RuntimeError: error raised -Homework -======== - -Python Power - - -Assignments ------------ -Task 1: Timing Context Manager +LAB +---- +**Timing Context Manager** -Create a context manager that will print to stdout the elapsed time taken to +Create a context manager that will print the elapsed time taken to run all the code inside the context: .. code-block:: ipython @@ -1019,29 +806,23 @@ run all the code inside the context: object as an argument (the default should be sys.stdout). The results of the timing should be printed to the file-like object. +Projects +-------- -.. nextslide:: - -Task 2: ``p-wrapper`` Decorator - -Write a simple decorator you can apply to a function that returns a string. -Decorating such a function should result in the original output, wrapped by an -HTML 'p' tag: - -.. code-block:: ipython +Projects due this Sunday. We'll review them early next week. If you turn +it in early, we should review it sooner. - In [4]: @p_wrapper - ...: def return_a_string(string): - ...: return string - ...: +To turn in: + * Put up it up gitHub, and do a pull request + * Put it in its own gitHub repository and point me to it. + * zip up the code an email it to me. - In [5]: return_a_string("this is a string") - Out[5]: '

        this is a string

        ' - -.. nextslide:: +PythonCHB@gmail.com -Task 3: Generator Homework (documented above) +Please do the online course evaluation -Task 4: Iterator Homework (documented above) +Anyone want office hours Sunday? +Or another time? +Keep writing Python! \ No newline at end of file diff --git a/_sources/supplements/git_overview.txt b/_sources/supplements/git_overview.txt new file mode 100644 index 00000000..3b9921eb --- /dev/null +++ b/_sources/supplements/git_overview.txt @@ -0,0 +1,235 @@ +.. _supplement_git_states: + +============ +git Overview +============ + + +Resources +========= + +.. rst-class:: left + Here are few good places to look for more info about using git: + + + **Pro git** + + The semi-offical documentation -- the first few chapters are worth going through: + + https://git-scm.com/book/en + + Reading suggested at the end of session 1: + + http://rogerdudler.github.io/git-guide/ + + + https://try.github.io/levels/1/challenges/1 + + + ** git Branching: getting fancy ** + + Interactive tutorial about branching -- try it right in the browser! + + http://pcottle.github.io/learnGitBranching/ + + +A Graphical Tutorial +==================== + +A Picture of git +---------------- + +.. figure:: /_static/git_simple_timeline.png + :width: 80% + :class: center + +.. rst-class:: build +.. container:: + + A git repository is a set of points in time, with history showing where + you've been. + + Each point has a *name* (here *A*, *B*, *C*) that uniquely identifies it, + called a *hash* + + The path from one point to the previous is represented by the *difference* + between the two points. + +.. nextslide:: + +.. figure:: /_static/git_head.png + :width: 75% + :class: center + +.. rst-class:: build +.. container:: + + Each point in time can also have a label that points to it. + + One of these is *HEAD*, which always points to the place in the timeline + that you are currently looking at. + +.. nextslide:: + +.. figure:: /_static/git_master_branch.png + :width: 75% + :class: center + +.. rst-class:: build +.. container:: + + You may also be familiar with the label "master". + + This is the name that git automatically gives to the first *branch* in a + repository. + + A *branch* is actually just a label that points to a specific point in + time. + +.. nextslide:: + +.. figure:: /_static/git_new_commit.png + :width: 75% + :class: center + +.. rst-class:: build +.. container:: + + When you make a *commit* in git, you add a new point to the timeline. + + The HEAD label moves to this new point. + + So does the label for the *branch* you are on. + +.. nextslide:: Making a Branch + +.. figure:: /_static/git_new_branch.png + :width: 75% + :class: center + +.. rst-class:: build +.. container:: + + You can make a new *branch* with the ``branch`` command. + + This adds a new label to the current commit. + + Notice that it *does not* check out that branch. + +.. nextslide:: Making a Branch + +.. figure:: /_static/git_checkout_branch.png + :width: 75% + :class: center + +.. rst-class:: build +.. container:: + + You can use the ``checkout`` command to switch to the new branch. + + This associates the HEAD label with the *session01* label. + + Use ``git branch`` to see which branch is *active*:: + + $ git branch + master + * session01 + +.. nextslide:: Making a Branch + +.. figure:: /_static/git_commit_on_branch.png + :width: 75% + :class: center + +.. rst-class:: build +.. container:: + + While it is checked out, new commits move the *session01* label. + + Notice that HEAD is *always* the same as "where you are now" + +.. nextslide:: Making a Branch + +You can use this to switch between branches and make changes in isolation. + +.. rst-class:: build +.. container:: + + .. figure:: /_static/git_checkout_master.png + :width: 75% + :class: center + + .. figure:: /_static/git_new_commit_on_master.png + :width: 75% + :class: center + +.. nextslide:: Merging Branches + +.. rst-class:: build +.. container:: + + Branching allows you to keep related sets of work separate from each-other. + + In class here, you can use it to do your exercises for each session. + + Simply create a new branch for each session from your repository master + branch. + + Do your work on that branch, and then you can issue a **pull request** in + github to have your work evaluated. + + This is very much like how teams work in the "real world" so learning it + here will help you. + + The final step in the process is merging your work. + +.. nextslide:: Merging Branches + +The ``merge`` command allows you to *combine* your work on one branch with the +work on another. + +.. rst-class:: build +.. container:: + + It creates a new commit which reconciles the differences: + + .. figure:: /_static/git_merge_commit.png + :width: 75% + :class: center + + Notice that this commit has **two** parents. + + +.. nextslide:: Conflicts + +.. rst-class:: build +.. container:: + + Sometimes when you ``merge`` two branches, you get *conflicts*. + + This happens when the same file was changed in about the same place in two + different ways. + + Often, git can work these types of things out on its own, but if not, + you'll need to manually edit files to fix the problem. + + You'll be helped by the fact that git will tell you which files are in + conflict. + + Just open those files and look for conflict markers: + + * <<<<<<<<< *hash1* (stuff from the current branch) + * ========= (the pivot point between two branches' content) + * >>>>>>>>> *hash2* (stuff from the branch being merged) + +.. nextslide:: Conflicts + +Your job in fixing a conflict is to decide exactly what to keep. + +You can (and should) communicate with others on your team when doing this. + +Always remember to remove the conflict markers too. They are not syntactic +code in any language and will cause errors. + +Once a conflict is resolved, you can ``git add`` the file back and then commit +the merge. diff --git a/_sources/supplements/index.txt b/_sources/supplements/index.txt new file mode 100644 index 00000000..07d4a91d --- /dev/null +++ b/_sources/supplements/index.txt @@ -0,0 +1,8 @@ +********************** +Supplemental Materials +********************** + +.. toctree:: + :maxdepth: 1 + + unicode diff --git a/_sources/supplements/install_nano_win.txt b/_sources/supplements/install_nano_win.txt new file mode 100644 index 00000000..1fc21dc5 --- /dev/null +++ b/_sources/supplements/install_nano_win.txt @@ -0,0 +1,22 @@ +.. _supplement_install_nano_win: + + +Installing Nano on Windows +========================== + +.. slide:: Installing Nano on Windows + :level: 3 + + For all Windows installations, download the WinNT/9x binary from here: + + http://www.nano-editor.org/download.php + + Unzip the file and move the files into the git bin directory: C:\Program Files\Git\bin + + That's it! You should now be able to use nano from git bash: + + .. code-block:: bash + + $ nano test.txt + + Command shortcuts are helpfully written in the editor! \ No newline at end of file diff --git a/_sources/supplements/packaging.txt b/_sources/supplements/packaging.txt new file mode 100644 index 00000000..a9760fca --- /dev/null +++ b/_sources/supplements/packaging.txt @@ -0,0 +1,481 @@ +====================== +Packages and Packaging +====================== + +Modules and Packages +-------------------- + +A module is a file (``something.py``) with python code in it + +A package is a directory with an ``__init__.py`` file in it + +And usually other modules, packages, etc... + +:: + + my_package + __init__.py + module_a.py + module_b.py + + +.. code-block:: python + + import my_package + + +runs the code ``my_package/__init__.py`` (if there is any) + +Modules and Packages +-------------------- + +.. code-block:: python + + import sys + for p in sys.path: + print p + +(demo) + +Installing Python +----------------- + +Linux: + +Usually part of the system -- just use it. + +Windows: + +Use the python.org version: + +* System Wide + +* Can install multiple versions if need be + +* Third party binaries for it. + +Installing Python +----------------- +OS-X: + +Comes with the system, but: + + * Apple has never upgraded within a release + * There are non-open source components + * Third party packages may or may not support it + * Apple does use it -- so don't mess with it + * I usually recommend the ``python.org`` version + +(Also Macports, Fink, Home Brew...) + + +Distributions +------------- + +There are also a few "curated" distributions: + +These provide python and a package management system for hard-to-buid packages. + +Widely used by the scipy community +(lots of hard to build stuff that needs to work together...) + + * Anaconda (https://store.continuum.io/cshop/anaconda/) + * Canopy (https://www.enthought.com/products/canopy/) + * ActivePython (http://www.activestate.com/activepython) + + +Installing Packages +------------------- +Every Python installation has its own stdlib and ``site-packages`` folder + +``site-packages`` is the default place for third-party packages + +Finding Packages +---------------- +The Python Package Index: + +**PyPi** + +http://pypi.python.org/pypi + +Installing Packages +------------------- +.. rst-class:: medium + + **From source** + +* (``setup.py install`` ) + +* With the system installer (apt-get, yum, etc...) + +.. rst-class:: medium + + **From binaries:** + +* Windows: MSI installers + +* OS-X: dmg installers (make sure to get compatible packages) + +* And now: binary wheels -- (More and more of those available) + +* ``pip`` should find appropriate binary wheels if they are there. + + +.. nextslide:: + +In the beginning, there was the ``distutils``: + +But ``distutils`` is missing some key features: + +* package versioning +* package discovery +* auto-install + +- And then came ``PyPi`` + +- And then came ``setuptools`` + +- But that wasn't well maintained... + +- Then there was ``distribute/pip`` + +- Which has now been merged back into ``setuptools`` + +Now it's pretty stable: pip+setuptools: use them. + +Installing Packages +------------------- + +Actually, it's still a bit of a mess + +But getting better, and the mess is *almost* cleaned up. + +Current State of Packaging +-------------------------- + +To build packages: distutils + + * http://docs.python.org/2/distutils/ + +For more features: setuptools + + * https://pythonhosted.org/setuptools/ + +To install packages: pip + + * https://pip.pypa.io/en/latest/installing.html + +For binary packages: wheels + + * http://www.python.org/dev/peps/pep-0427/ + +(installable by pip) + +Compiled Packages +----------------- + +Biggest issue is with compiled extensions: + + * (C/C++, Fortran, etc.) + + * You need the right compiler set up + +Dependencies: + + * Here's were it gets really ugly + + * Particularly on Windows + +.. nextslide:: + +**Linux** + +Pretty straightforward: + +1. Is there a system package? + + * use it (apt-get install the_package) + +2. Try ``pip install``: it may just work! + +3. Install the dependencies, build from source:: + + python setup.py build + + python setup.py install + +(may need "something-devel" packages) + + +.. nextslide:: + +**Windows** + +Sometimes simpler: + +1) A lot of packages have Windows binaries: + + - Usually for python.org builds + - Excellent source: http://www.lfd.uci.edu/~gohlke/pythonlibs/ + - Make sure you get 32 or 64 bit consistent + +2) But if no binaries: + + - Hope the dependencies are available! + - Set up the compiler + +MS now has a compiler just for python! + +http://www.microsoft.com/en-us/download/details.aspx?id=44266 + +.. nextslide:: + +**OS-X** + +Lots of Python versions: + - Apple's built-in (different for each version of OS) + - python.org builds + - 32+64 bit Intel (and even PPC still kicking around) + - Macports + - Homebrew + +Binary Installers (dmg or wheel) have to match python version + +.. nextslide:: + +**OS-X** + +If you have to build it yourself + +Xcode compiler (the right version) + + - Version 3.* for 32 bit PPC+Intel + + - Version > 4.* for 32+64 bit Intel + +(make sure to get the SDKs for older versions) + +If extra dependencies: + + - macports or homebrew often easiest way to build them + + +Final Recommendations +--------------------- + +First try: ``pip install`` + +If that doesn't work: + +Read the docs of the package you want to install + +Do what they say + +(Or use Anaconda or Canopy) + +virtualenv +---------- + +``virtualenv`` is a tool to create isolated Python environments. + +Very useful for developing multiple apps + +Or deploying more than one app on one system + +http://www.virtualenv.org/en/latest/index.html} + +Remember the notes from the beginning of class? :ref:`virtualenv_section` + +(Cris will probably make you do this next class) + +============ +Distributing +============ + +Distributing +------------ +What if you need to distribute you own: + +Scripts + +Libraries + +Applications + + +Scripts +------- + +Often you can just copy, share, or check in the script to source +control and call it good. + +But only if it's a single file, and doesn't need anything non-standard + +When the script needs more than just the stdlib + +(or your company standard environment) + +You have an application, not a script + + +Libraries +--------- + +When you read the distutils docs, it's usually libraries they're talking about + +Scripts + library is the same... + +(http://docs.python.org/distutils/) + +distutils +--------- + +``distutils`` makes it easy to do the easy stuff: + +Distribute and install to multiple platforms, etc. + +Even binaries, installers and compiled packages + +(Except dependencies) + +(http://docs.python.org/distutils/) + +distutils basics +---------------- + +It's all in the ``setup.py file``: + +.. code-block::python + + from distutils.core import setup + setup(name='Distutils', + version='1.0', + description='Python Distribution Utilities', + author='Greg Ward', + author_email='gward@python.net', + url='http://www.python.org/sigs/distutils-sig/', + packages=['distutils', 'distutils.command'], + ) + +(http://docs.python.org/distutils/) + +distutils basics +---------------- + +Once your setup.py is written, you can: + +:: + + python setup.py ... + build build everything needed to install + install install everything from build directory + sdist create a source distribution + (tarball, zip file, etc.) + bdist create a built (binary) distribution + bdist_rpm create an RPM distribution + bdist_wininst create an executable installer for MS Windows + upload upload binary package to PyPI + +wheels +------ + +"wheels" are the "new" package format for python. + +A wheel is essentially a zip file of the entire package, ready to be +unpacked in the right place on installation. + +``pip`` will look for wheels for OS-X and Windows on PyPi, and auto-install +them if they exist + +This is particularly nice for packages with non-python dependencies. + + +More complex packaging +---------------------- + +For a complex package: + +You want to use a well structured setup: + +http://the-hitchhikers-guide-to-packaging.readthedocs.org/en/latest/ + +develop mode +------------ + +While you are developing your package, Installing it is a pain. + +But you want your code to be able to import, etc. as though it were installed + +``setup.py develop`` installs links to your code, rather than copies +-- so it looks like it's installed, but it's using the original source + +``python setup.py develop`` + +You need ``setuptools`` and a setup.py to use it. + + +Applications +------------ + +For a complete application: + + * Web apps + * GUI apps + +Multiple options: + + * Virtualenv + VCS + * zc.buildout ( http://www.buildout.org/} + * System packages (rpm, deb, ...) + * Bundles... + + +Bundles +------- + +Bundles are Python + all your code + plus all the dependencies -- +all in one single "bundle" + +Most popular on Windows and OS-X + +:: + + py2exe + py2app + pyinstaller + ... + + +User doesn't even have to know it's python + +Examples: + + http://www.bitpim.org/ + + http://response.restoration.noaa.gov/nucos + +LAB +--- + +Write a setup.py for a script of yours + + * Ideally, your script relies on at least one other module + * At a minimum, you'll need to specify ``scripts`` + * and probably ``py_modules`` + * try: + + * ``python setup.py build`` + * ``python setup.py install`` + * ``python setup.py sdist`` + + * EXTRA: install ``setuptools`` + + * use: ``from setuptools import setup`` + * try: `` python setup.py develop`` + + * EXTRA2: install ``wheel`` + + * ``python setup.py bdist_wheel`` + + +(my example: ``Examples/Session09/capitalize``) diff --git a/_sources/supplements/python_for_linux.txt b/_sources/supplements/python_for_linux.txt new file mode 100644 index 00000000..058b26cd --- /dev/null +++ b/_sources/supplements/python_for_linux.txt @@ -0,0 +1,230 @@ +.. _python_for_linux: + +****************************** +Setting Up Python For Linux +****************************** + + +================================================== +Debian and Related Distros (Ubuntu, Linux Mint) +================================================== + +Python +------- + +Debian distros already have the stable python2 and python3 releases preinstalled [`1 `_]. Try the following commands: + +.. code-block:: bash + + $ python2 + Python 2.7.9 (default, April 2 2015, 15:33:32) + [GCC 4.9.2 on linux2] + >>> + +.. code-block:: bash + + $ python3 + Python 3.4.3 (default, March 26 2015, 15:33:32) + [GCC 4.9.2 on linux] + >>> + +That's nice, which one is the default version? Just type ``python`` to see. It's probably python2 still: + +.. code-block:: bash + + $ python + Python 2.7.9 (default, April 2 2015, 15:33:32) + [GCC 4.9.2 on linux2] + >>> + +If you want to make ``python3.4`` the default version then add the line ``alias python=python3`` to your user's ``/home/{user}/.bashrc`` file like so: + +.. code-block:: bash + + $ # before the change + $ python + Python 2.7.9 (default, April 2 2015, 15:33:32) + [GCC 4.9.2 on linux2] + >>> + + $ echo "alias python=python3" >> ~/.bashrc + $ source ~/.bashrc + + $ # after the change + $ python + Python 3.4.3 (default, March 26 2015, 15:33:32) + [GCC 4.9.2 on linux] + >>> + +If you don't have the version you want installed then use the package manager to find and install it: + +.. code-block:: bash + + $ # search the package manager for it + $ sudo apt-cache search python | grep '^python3.4\ -' + python3.4 - Interactive high-level object-oriented language (version 3.4) + $ # install it + $ sudo apt-get install python3.4 + + +Terminal +--------- + +Every Linux box has a terminal emulator -- find and use it. + + +git +---- + +Git is likely to be there on your system already, but if not: + +.. code-block:: bash + + $ sudo apt-get install git + +pip +--- + +``pip`` is the Python package installer. + +Many python packages are also available directly from your distro -- but you'll get the latest and greatest if you use ``pip`` to install it instead. + +To get pip, the first option is to use your system package manager, something like: + +.. code-block:: bash + + $ sudo apt-get install python3-pip + +If that doesn't work, then look up the `official manual install notes `_ + +iPython +-------- + +One we are going to use in class is ``iPython``:: + + $ sudo pip3 install ipython[all] + +You should now be able to run ``iPython``:: + + $ ipython3 + Python 3.4.3 () + Type "copyright", "credits" or "license" for more information. + + IPython 2.0.0 -- An enhanced Interactive Python. + ? -> Introduction and overview of IPython's features. + %quickref -> Quick reference. + help -> Python's own help system. + object? -> Details about 'object', use 'object??' for extra details. + + + +================================================== +Fedora and Red Hat Related Distros (CentOS) +================================================== + +.. warning:: + + CentOS is probably the most popular distro of these related flavors. However, getting Python3 on it can be a pain. You have been warned + +Python +------- + +Fedora distros already have the stable python2 and python3 releases preinstalled `[2] `_. However, CentOS, the most popular distro only has the stable python2 release. Try the following commands: + +.. code-block:: bash + + [centos@ip-172-31-21-5 ~]$ python2 + Python 2.7.5 (default, Jun 17 2014, 18:11:42) + [GCC 4.8.2 20140120 (Red Hat 4.8.2-16)] on linux2 + Type "help", "copyright", "credits" or "license" for more information. + >>> + + [centos@ip-172-31-21-5 ~]$ python3 + -bash: python3: command not found + + +Let's install python3 using the package manager. Step one install `Software Collections` to help us: + +.. code-block:: bash + + $ sudo yum -y install scl-utils + +Then go to the `software collections listing `_ and click on the python collection version you want to install. Note, you also need to know which version of CentOS you are using (probably 6 or 7). For example, we care about `python version 3.4` so let's go the `.rpm` i want to install `here `_: + +.. code-block:: bash + + $ # add this package to the rpm package manager + $ sudo rpm -Uvh https://www.softwarecollections.org/repos/rhscl/rh-python34/epel-7-x86_64/noarch/rhscl-rh-python34-epel-7-x86_64.noarch.rpm + + $ # install the right python version + $ sudo yum install rh-python34 + +When you want to use python3 run this command: + +.. code-block:: bash + + [centos@ip-172-31-21-5 ~]$ scl enable rh-python34 bash + + + + +Terminal +--------- + +Every Linux box has a terminal emulator -- find and use it. + + +git +---- + +Git is likely to be there on your system already, but if not: + +.. code-block:: bash + + $ sudo yum install git + +pip +--- + +``pip`` is the Python package installer. + +Many python packages are also available directly from your distro -- but you'll get the latest and greatest if you use ``pip`` to install it instead. + +In CentOS, if you used the above technique to install Python3, then it comes with pip. Try: + +.. code-block:: bash + + [centos@ip-172-31-21-5 ~]$ pip -V + pip 1.5.6 from /opt/rh/rh-python34/root/usr/lib/python3.4/site-packages (python 3.4) + +iPython +-------- + +One we are going to use in class is ``iPython``:: + + $ sudo pip install ipython[all] + +You should now be able to run ``iPython``:: + + $ ipython3 + Python 3.4.3 () + Type "copyright", "credits" or "license" for more information. + + IPython 2.0.0 -- An enhanced Interactive Python. + ? -> Introduction and overview of IPython's features. + %quickref -> Quick reference. + help -> Python's own help system. + object? -> Details about 'object', use 'object??' for extra details. + + +Footnotes: +=========== + +Debian Wiki +============= + https://wiki.debian.org/Python + +Fedora Wiki +============= + https://fedoraproject.org/wiki/Packaging:Python + diff --git a/_sources/supplements/python_for_mac.txt b/_sources/supplements/python_for_mac.txt new file mode 100644 index 00000000..8d82322b --- /dev/null +++ b/_sources/supplements/python_for_mac.txt @@ -0,0 +1,131 @@ +.. _python_for_mac: + +****************************** +Setting up your Mac for Python +****************************** + +================== +Getting The Tools +================== + +.. rst-class:: left + +OS-X comes with Python out of the box, but not the full setup you'll need for development, and this class. It also doesn't have the latest version(s), and no versino of Python 3. + +So we recommend installing a new version. + +.. rst-class:: left + +**Note**: + +.. rst-class:: left + +If you use ``macports`` or ``homebrew`` to manage \*nix software on your machine, feel free to use those for ``python``, ``git``, etc, as well. If not, then read on. + +Python +------ + +While OS-X does provide python out of the box -- it tends not to have the +latest version, and you really don't want to mess with the system +installation. So I recommend installing an independent installation from +``python.org``: + +Download and install Python 3.4.3 64/32 bit installer from Python.org: + +https://www.python.org/ftp/python/3.4.3/python-3.4.3-macosx10.6.pkg + +(you can probably use 3.5.0, too, but it's brand new, and there are a number of third party pacakges that are not yet available for it) + +Simple as that. + +Oddly, this does NOT install a ``python`` command, but rather a ``python3`` command. If you want to be able to simply type ``python`` and get python3, then you can add a symlink to the install:: + + $ cd /Library/Frameworks/Python.framework/Versions/3.5/bin + $ ln -s python3.5 python + +(or an alias in your shell -- an Unix geeks here?) + +Terminal +--------- + +The built-in "terminal" application works fine. Find it in: + +:: + + /Applications/Utilities/Terminal + +Drag it to the dock to easy access. + +git +---- + +Get a git client -- the gitHub GUI client may be nice -- I honestly don't know. + +There are a couple options for a command line client. + +This one: + +http://sourceforge.net/projects/git-osx-installer/ + +Is a big download and install, but has everything you need out of the box. + +NOTE: if you get a warnign about it beign unsigned, you'll need to go to yoru system preferences: + + "Security and Privacy" + + Then check the box saying "Open Anyway". Or maybe check the box saying you can install untrused pacakges -- depends on the OS-X version + +This one: + +http://git-scm.com/download/mac + +Works great, but you need the XCode command line tools to run it. If you already have that, or expect to need a compiler anyway, then this is a good option. + +You can get XCode from the Apple App Store. + +(If you try running "git" on the command line after installing, it should send you there). + +Warning: XCode is a BIG download. Once installed, run it so it can initialize itself. + +After either of these is installed, the ``git`` command should work: + +.. code-block:: bash + + $ git --version + git version 1.8.5.2 (Apple Git-48) + +pip +--- + +``pip`` is the Python package installer. It is updated faster than python itself, so once you have python, you want to get the latest version of pip working:: + + $ python -m ensurepip --upgrade + +[first make sure that ``python`` gives you the one you want. You may need to call ``python3`` instead] + +It should download and install the latest ``pip``. + +You can now use pip to install other packages. + +iPython +-------- + +One we are going to use in class is ``iPython``:: + + $ python3 -m pip install ipython[all] + +You should now be able to run ``iPython``:: + + Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19) + Type "copyright", "credits" or "license" for more information. + + IPython 4.0.0 -- An enhanced Interactive Python. + ? -> Introduction and overview of IPython's features. + %quickref -> Quick reference. + help -> Python's own help system. + object? -> Details about 'object', use 'object??' for extra details. + + + + + diff --git a/_sources/supplements/python_for_windows.txt b/_sources/supplements/python_for_windows.txt new file mode 100644 index 00000000..fa284be4 --- /dev/null +++ b/_sources/supplements/python_for_windows.txt @@ -0,0 +1,99 @@ +.. _python_for_windows: + +***************************** +Setting up Windows for Python +***************************** + +================== +Getting The Tools +================== + +Python +------- + +There are a number of python distributions available -- many designed for easier support of scientific programming: + +- Anaconda +- Enthought Canopy +- Python(x,y) + +But for core use, the installer from python.org is the way to go: + +https://www.python.org/downloads/ + +You want the installer for Python 3.x -- probably 64 bit, though if you have a 32 bit sytem, you can get that. There is essentially no difference for the purposes of this course. + +Double click and install. + + +Terminal +--------- + +If you are confident in your use of the "DOS Box" or "powershell", feel free to use one of those. However, your life may be easier if you install "Git Bash", as then you can follow unix-style terminal instructions exactly, and do not have to translate. Also, your instructors are more experienced with Bash. +From now on, if you hear the terms 'bash', 'shell' or 'terminal', know that this is the application that is being referred to. + +When you install Git Bash, you are installing git (and a git gui) as well, thus killing two birds with one stone, metaphorically speaking. + +https://git-for-windows.github.io/ + +This is actually your best bet for running Python also -- If you use the Git Bash shell, you can use the same commands as Linux and OS-X users. Regardless of which shell you choose, you will need to add Python to your environment. It is possible that this was done during the installation of python. If you type 'which python' into your terminal, and get back the answer '/c/python34/python', then you are good to go, otherwise, follow the instructions here: + +http://www.computerhope.com/issues/ch000549.htm + +Based on the subversion of Python you will want to add something like: + +``C:\Python34`` + +and + +``C:\Python34\Scripts`` + +to ``PATH`` + + +git +---- + +If you installed Git Bash, you will already have git, both usable in the terminal and as a gui, and can safely skip this section. If not, you still need a git client. You can use the above link and install git (it will install the bash shell as well, of course, but you can use your shell of choice instead). + +There is also TortoiseGit: + +https://code.google.com/p/tortoisegit/ + +which integrates git with the file manager. Feel free to use this if you already have an understanding of how git works, but for the purposes of learning, it may be better to use a command line client (git Bash above). + +pip +--- + +``pip`` is the Python package installer. It is updated faster than python itself, so once you have python you want to get the latest version of pip working:: + + $ python -m ensurepip --upgrade + +It should download and install the latest ``pip``. + +You can now use pip to install other packages. + +iPython +-------- + +One extra package we are going to use in class is ``iPython``:: + + $ pip install ipython[all] + +You should now be able to run ``iPython`` from the git bash shell:: + + $ ipython + Python 2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35) + Type "copyright", "credits" or "license" for more information. + + IPython 2.0.0 -- An enhanced Interactive Python. + ? -> Introduction and overview of IPython's features. + %quickref -> Quick reference. + help -> Python's own help system. + object? -> Details about 'object', use 'object??' for extra details. + +(or from the DOS box or PowerShell prompt) + +We will use this as our default python interpreter. + + diff --git a/slides_sources/source/supplements/python_learning_resources.rst b/_sources/supplements/python_learning_resources.txt similarity index 82% rename from slides_sources/source/supplements/python_learning_resources.rst rename to _sources/supplements/python_learning_resources.txt index d437aac2..829a1e03 100644 --- a/slides_sources/source/supplements/python_learning_resources.rst +++ b/_sources/supplements/python_learning_resources.txt @@ -1,6 +1,8 @@ -*********************************************************** +.. _python_learning_resources: + +********************************* Useful Python Learning Resources -*********************************************************** +********************************* In addition to the material we cover in class, there are numerous online resources to help a newcomer get to know Python. The following list represents @@ -8,20 +10,20 @@ the best-known and best-regarded of the breed. If you are itching for a bit more work on your Python chops, you should try these out. Python Language Resources -=============================== +========================== As a Python programmer, you'll want to keep a bookmark pointed at the -official Python documentation (https://docs.python.org/2/), especially +official Python documentation (https://docs.python.org/3/), especially the documentation for the standard library -(https://docs.python.org/2/library/index.html). However, there are a +(https://docs.python.org/3/library/index.html). However, there are a number of additional resources you can (and should) use to help build your Python chops. For the beginner ----------------------- +----------------- * **The Python Tutorial** - (https://docs.python.org/2/tutorial/): This is the + (https://docs.python.org/3/tutorial/): This is the official tutorial from the Python website. No more authoritative source is available. @@ -36,7 +38,7 @@ For the beginner programmed in any language before. * **Dive Into Python 3** - (http://www.diveinto.org/python3/): The updated version + (http://www.diveintopython3.net/): The updated version of a classic. This book offers an introduction to Python aimed at the student who has experience programming in another language. @@ -47,14 +49,14 @@ For the beginner * **Think Python** (http://greenteapress.com/thinkpython/): Methodical and - complete. This book offers a very "computer science"-style introduction to + complete. This book offers a very "computer science-style" introduction to Python. It is really an intro to Python *in the service of* Computer Science, though, so while helpful for the absolute newcomer, it isn't quite as "pythonic" as it might be. * **Core Python Programming** - (http://corepython.com/): Only available as a dead - trees version, but if you like to have book to hold in your hands anyway, this + (http://corepython.com/): Only available as a dead trees version, but + if you like to have book to hold in your hands anyway, this is the best textbook style introduction out there. It starts from the beginning, but gets into the full language. Published in 2009, but still in print, with updated appendixes available for new language features. @@ -82,12 +84,15 @@ Next Steps Evaluating Your Options ----------------------------- -The blurbs above are short descriptions of the material in each resource. I've -drawn them both from my own usage of the various tools, and from a wonderful -set of online reviews +The blurbs above are short descriptions of the material in each resource. We've +drawn them both from our own usage of the various tools, and from a wonderful +set of online reviews: + (http://planningadinner.blogspot.com/search/label/So%20you%20want%20to%20learn%20Python.%20What%27s%20next%3F) + done by Marta Maria Casetti on her blog, "Planning a Dinner" (http://planningadinner.blogspot.com/). + The poster she presented at PyCon 2014 (http://planningadinner.blogspot.com/2014/04/the-poster.html) as a result of that research offers some great hints about the aspects of @@ -96,12 +101,12 @@ of Python to take the time to look over this poster to help determine the best path forward for themselves. iPython Interpreter Resources -================================== +============================= iPython is an enhanced interpreter that makes interactive experimentation at the command line much more pleasant and powerful. * **The iPython tutorial** - (http://ipython.org/ipython-doc/rel-0.10.2/html/interactive/tutorial.html) + (https://ipython.org/ipython-doc/stable/interactive/tutorial.html) * **Using IPython for interactive work** (http://ipython.org/ipython-doc/stable/interactive/index.html) @@ -110,3 +115,4 @@ iPython is an enhanced interpreter that makes interactive experimentation at the * **The iPython Documentation** (http://ipython.org/ipython-doc/stable/index.html) Use this to learn more about iPython's amazing capabilities. + diff --git a/slides_sources/source/supplements/shell.rst b/_sources/supplements/shell.txt similarity index 99% rename from slides_sources/source/supplements/shell.rst rename to _sources/supplements/shell.txt index edc554ff..552cac01 100644 --- a/slides_sources/source/supplements/shell.rst +++ b/_sources/supplements/shell.txt @@ -1,3 +1,5 @@ +.. _shell_customization: + ******************************************* Shell Customizations for Python Development ******************************************* @@ -178,7 +180,7 @@ actually print something else entirely: $ echo ${PARAM:+'foo'} foo $ echo ${PARAM:+'bar'} - + $ The key here is the ``:`` bit immediately after ``PARAM``. If the ``+`` @@ -202,7 +204,7 @@ no virtualenv was active: .. code-block:: bash $ echo ${VIRTUAL_ENV:+[`basename $VIRTUAL_ENV`]} - + $ source /path/to/someenv/bin/activate $ echo ${VIRTUAL_ENV:+[`basename $VIRTUAL_ENV`]} someenv diff --git a/slides_sources/source/supplements/sublime_as_ide.rst b/_sources/supplements/sublime_as_ide.txt similarity index 89% rename from slides_sources/source/supplements/sublime_as_ide.rst rename to _sources/supplements/sublime_as_ide.txt index 489efd14..1f9a115a 100644 --- a/slides_sources/source/supplements/sublime_as_ide.rst +++ b/_sources/supplements/sublime_as_ide.txt @@ -1,3 +1,5 @@ +.. _sublime_as_ide: + ************************************************** Turning Sublime Text Into a Lightweight Python IDE ************************************************** @@ -29,8 +31,9 @@ Here are *my* requirements for an 'IDE': Which Version? ============== -Version 2 will be fine, but I would urge you to consider updating to version 3. -Some of the plugins I recommend are not available for version 2. +While Version 3 is still considered "beta", it is the one everyone is putting +their effort into, and some of the plugins I recommend are not available for +version 2. Basic Settings @@ -63,8 +66,10 @@ are quite personal, find ones that suit you.): "color_scheme": "Packages/User/Cobalt (SL).tmTheme", "theme": "Soda Light 3.sublime-theme", // A font face that helps distinguish between 0 (the number) and 'O' (the letter) - // among other problem characters. - "font_face": "DroidSansMonoSlashed", + // among other problem characters. YOu also want a "fixed width font" + // Monaco is a nice option that comes with all Macs. + // Not sure what's best on Windows. + "font_face": "Monaco", // getting older. I wonder if comfy font size increases as a linear // function of age? "font_size": 15, @@ -85,9 +90,9 @@ are quite personal, find ones that suit you.): "tab_size": 4, "translate_tabs_to_spaces": true, "use_tab_stops": true, + "draw_white_space": "all", // I like so see spaces and tabs -- makes it easier to debug } - Especially important is the setting ``translate_tabs_to_spaces``, which ensures that any time you hit a tab key, the single ``\t`` character is replaced by four ``\s`` characters. In Python this is **vital**! @@ -109,9 +114,10 @@ Python! To install a plugin using Package Control, open the ``command palette`` with -``shift-super-P`` (``ctrl-shift-P`` on Windows/Linux). The ``super`` key is ``command`` -or ``⌘`` on OS X. When the palette opens, typing ``install`` will bring up the -``Package Control: Install Package`` command. Hit ``enter`` to select it. +``shift-super-P`` (``ctrl-shift-P`` on Windows/Linux). The ``super`` key is +``command`` or ``⌘`` on OS X. When the palette opens, typing ``install`` will +bring up the ``Package Control: Install Package`` command. Hit ``enter`` to +select it. .. image:: /_static/pc_menu.png :width: 600px @@ -176,7 +182,7 @@ The ``python_interpreter_path`` allows me to indicate which Python executable should be introspected for symbol definitions. The ``python_package_paths`` setting allows designating additional paths that -will be searched for Python packages containing symbols. +will be searched for Python packages containing symbols. .. image:: /_static/tab_completion.png :width: 600px @@ -218,26 +224,19 @@ There is a nice plugin for the SublimeLinter that `utilizes flake8`_. For it to work, the plugin will need to have a Python executable that has the Python tools it needs installed. -Use `virtualenv`_ to accomplish this. First, create a virtualenv and activate -it: -.. _utilizes flake8: https://sublime.wbond.net/packages/SublimeLinter-flake8 -.. _virtualenv: http://virtualenv.org -.. code-block:: bash +Make sure that the python packages you need are installed in your main +python install, rather than a virtualenv. + - $ cd /Users/cewing/virtualenvs - $ virtualenv sublenv - New python executable in sublenv/bin/python - Installing setuptools, pip...done. - $ source sublenv/bin/activate - (sublenv)$ +.. _utilizes flake8: https://sublime.wbond.net/packages/SublimeLinter-flake8 -Then use Python packaging tools to install the required packages: +Use Python packaging tools to install the required packages: .. code-block:: bash - (sublenv)$ pip install flake8 + $ pip install flake8 Downloading/unpacking flake8 [...] Downloading/unpacking pyflakes>=0.7.3 (from flake8) @@ -250,18 +249,16 @@ Then use Python packaging tools to install the required packages: [...] Successfully installed flake8 pyflakes pep8 mccabe Cleaning up... - (sublenv)$ - -The Python executable for this ``virtualenv`` now has the required packages -installed. You can look in ``/path/to/sublenv/bin`` to see the executable -commands for each: - - (sublenv)$ ls sublenv/bin - activate easy_install-2.7 pip2.7 - activate.csh flake8 pyflakes - activate.fish pep8 python - activate_this.py pip python2 - easy_install pip2 python2.7 + $ + +Your Python install now has the required packages installed. + +try typeing these command to make sure:: + + $ flake8 + Usage: flake8 [options] input ... + + flake8: error: input not specified Now install SublimeLinter and then SublimeLinter-flake8 using Package Control. diff --git a/_sources/supplements/unicode.txt b/_sources/supplements/unicode.txt new file mode 100644 index 00000000..80d9b0b0 --- /dev/null +++ b/_sources/supplements/unicode.txt @@ -0,0 +1,537 @@ +.. Another verison os the Unicode discussion +.. -- I think there is a bit in here that we'll want to use. + + +Unicode +======= + +.. rst-class:: left + + I hope you all read this: + + The Absolute Minimum Every Software Developer Absolutely, + Positively Must Know About Unicode and Character Sets (No Excuses!) + + http://www.joelonsoftware.com/articles/Unicode.html + + If not -- go read it! + +Fact number 1: +-------------- + +.. rst-class:: centered medium + + Everything is made up of bytes + +If it's on disk or transmitted over a network, it's bytes + +Python provides some abstractions to make it easier to deal with bytes + +Unicode is a biggie + +Actually, dealing with numbers rather than bytes is big -- but we take that for granted + + +What the heck is Unicode anyway? +--------------------------------- + +* First there was chaos... + + * Different machines used different encodings + +* Then there was ASCII -- and all was good (7 bit), 127 characters + + * (for English speakers, anyway) + +* But each vendor used the top half (127-255) for different things. + + * macroman, Windows 1252, etc... + + * There is now "latin-1", but still a lot of old files around + +* Non Western-European languages required totally incompatible 1-byte + encodings + +* No way to mix languages with different alphabets. + +Fact number 2: +-------------- + +.. rst-class:: centered medium + + The world needs more than 255 charactors. + +.. rst-class:: centered + + Hello, world! • Здравствуй, мир! + + Բարեւ, աշխարհի! • !مرحبا ، العالم + + !שלום, עולם • 여보세요 세계! + + नमस्ते, दुनिया! • 你好,世界! + + +Enter Unicode +-------------- + +The Unicode idea is pretty simple: + + * one "code point" for all characters in all languages + +But how do you express that in bytes? + * Early days: we can fit all the code points in a two byte integer (65536 characters) + + * Turns out that didn't work -- we now need 32 bit integer to hold all of unicode + "raw" (UTC-4) -- well we don't need quite that many, but common machines don't have + 24 bit integers. + +Enter "encodings": + * An encoding is a way to map specific bytes to a code point. + + * Each code point can have one or more bytes. + + +Mechanics +========= + +What are strings? +----------------- + +Py2 strings are sequences of bytes + +Unicode strings are sequences of platonic characters + +It's almost one code point per character -- but there are complications +with combined characters: accents, etc. (we can ignore those most of the time) + +Platonic characters cannot be written to disk or network! + +(ANSI: one character == one byte -- so easy!) + + +str vs unicode +------------------- + +Python 2 has two types that let you work with text: + +* ``str`` + +* ``unicode`` + +And two ways to work with binary data: + +* ``str`` + +* ``bytes()`` (and ``bytearray``) + +**but:** + +.. code-block:: ipython + + In [86]: str is bytes + Out[86]: True + +``bytes`` is there for py3 compatibility -- but it's good for making your +intentions clear, too. + + +Unicode +-------- + +The ``unicode`` object lets you work with characters + +It has all the same methods as the string object. + +"encoding" is converting from a unicode object to bytes + +"decoding" is converting from bytes to a unicode object + +(sometimes this feels backwards...) + + +Using unicode in Py2 +--------------------- + +Built in functions + +.. code-block:: python + + ord() + chr() + unichr() + str() + unicode() + +The codecs module + +.. code-block:: python + + import codecs + codecs.encode() + codecs.decode() + codecs.open() # better to use ``io.open`` + + +Encoding and Decoding +---------------------- + +Encoding + +.. code-block:: ipython + + In [17]: u"this".encode('utf-8') + Out[17]: 'this' + + In [18]: u"this".encode('utf-16') + Out[18]: '\xff\xfet\x00h\x00i\x00s\x00' + +Decoding + +.. code-block:: ipython + + In [99]: print '\xff\xfe."+"x\x00\xb2\x00'.decode('utf-16') + ∮∫x² + + + +Unicode Literals +------------------ + +1) Use unicode in your source files: + +.. code-block:: python + + # -*- coding: utf-8 -*- + +2) escape the unicode characters: + +.. code-block:: python + + print u"The integral sign: \u222B" + print u"The integral sign: \N{integral}" + +Lots of tables of code points online: + +One example: + http://inamidst.com/stuff/unidata/ + +:download:`hello_unicode.py <./hello_unicode.py>`. + + +Using Unicode +-------------- + +Use ``unicode`` objects in all your code + +Decode on input + +Encode on output + +Many packages do this for you: *XML processing, databases, ...* + +**Gotcha:** + +Python has a default encoding (usually ascii) + +.. code-block:: ipython + + In [2]: sys.getdefaultencoding() + Out[2]: 'ascii' + +The default encoding will get used in unexpected places! + + +Using unicode everywhere +------------------------- + +Python 2.6 and above have a nice feature to make it easier to use unicode everywhere + +.. code-block:: python + + from __future__ import unicode_literals + +After running that line, the ``u''`` is assumed + +.. code-block:: ipython + + In [1]: s = "this is a regular py2 string" + In [2]: print type(s) + + + In [3]: from __future__ import unicode_literals + In [4]: s = "this is now a unicode string" + In [5]: type(s) + Out[5]: unicode + +NOTE: You can still get py2 strings from other sources! + + +Encodings +--------- + +What encoding should I use??? + +There are a lot: + +http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings + +But only a couple you are likely to need: + +* utf-8 (``*nix``) +* utf-16 (Windows) + +And of course, still the one-bytes ones. + +* ASCII +* Latin-1 + +UTF-8 +----- + +Probably the one you'll use most -- most common in Internet protocols (xml, JSON, etc.) + +Nice properties: + +* ASCII compatible: first 127 characters are the same + +* Any ascii string is a utf-8 string + +* compact for mostly-english text. + +Gotchas: + +* "higher" code points may use more than one byte: up to 4 for one character + +* ASCII compatible means in may work with default encoding in tests -- but then blow up with real data... + +UTF-16 +------ + +Kind of like UTF-8, except it uses at least 16bits (2 bytes) for each character: not ASCII compatible. + +But it still needs more than two bytes for some code points, so you still can't assume two byte per character. + +In C/C++ held in a "wide char" or "wide string". + +MS Windows uses UTF-16, as does (I think) Java. + +UTF-16 criticism +---------------- + +There is a lot of criticism on the net about UTF-16 -- it's kind of the worst of both worlds: + +* You can't assume every character is the same number of bytes +* It takes up more memory than UTF-8 + +`UTF-16 Considered Harmful `_ + +But to be fair: + +Early versions of Unicode: everything fit into two bytes (65536 code points). + +MS and Java were fairly early adopters, and it seemed simple enough to just use 2 bytes per character. + +When it turned out that 4 bytes were really needed, they were kind of stuck in the middle. + +Latin-1 +-------- + +**NOT Unicode**: + +a 1-byte per char encoding. + +* Superset of ASCII suitable for Western European languages. + +* The most common one-byte-per-char encoding for European text. + +* Nice property -- every byte value from 0 to 255 is a valid character ( at least in Python ) + +.. nextslide:: + +* You will never get an UnicodeDecodeError if you try to decode arbitrary bytes with latin-1. + +* And it can "round-trip" through a unicode object. + +* Useful if you don't know the encoding -- at least it won't raise an Exception + +* Useful if you need to work with combined text+binary data. + +:download:`latin1_test.py <./latin1_test.py>`. + + +Unicode Docs +------------ + +Python Docs Unicode HowTo: + +http://docs.python.org/howto/unicode.html + +"Reading Unicode from a file is therefore simple" + +.. code-block:: python + + import io + f = io.open('hello_unicode.py', encoding='utf-8') + for line in f: + print repr(line) + + +Encodings Built-in to Python: + http://docs.python.org/2/library/codecs.html#standard-encodings + + +Gotchas in Python 2 +------------------- + +file names, etc: + +If you pass in unicode, you get unicode + +.. code-block:: ipython + + In [9]: os.listdir('./') + Out[9]: ['hello_unicode.py', 'text.utf16', 'text.utf32'] + + In [10]: os.listdir(u'./') + Out[10]: [u'hello_unicode.py', u'text.utf16', u'text.utf32'] + +Python deals with the file system encoding for you... + +But: some more obscure calls don't support unicode filenames: + +``os.statvfs()`` (http://bugs.python.org/issue18695) + + +.. nextslide:: + +Exception messages: + + * Py2 Exceptions use str when they print messages. + + * But what if you pass in a unicode object? + + * It is encoded with the default encoding. + + * ``UnicodeDecodeError`` Inside an Exception???? + + NOPE: it swallows it instead. + +:download:`unicode_exception_test.py <./unicode_exception_test.py>`. + +Unicode in Python 3 +---------------------- + +The "string" object is unicode. + +Py3 has two distinct concepts: + +* "text" -- uses the str object (which is always unicode!) +* "binary data" -- uses bytes or bytearray + +Everything that's about text is unicode. + +Everything that requires binary data uses bytes. + +It's all much cleaner. + +(by the way, the recent implementations are very efficient...) + + + +Basic Unicode LAB +================= + +.. rst-class left + +* Find some nifty non-ascii characters you might use. + + - Create a unicode object with them in two different ways. + - :download:`here <./hello_unicode.py>` is one example + +* Read the contents into unicode objects: + + - :download:`ICanEatGlass.utf8.txt <./ICanEatGlass.utf8.txt>` + - :download:`ICanEatGlass.utf16.txt <./ICanEatGlass.utf16.txt>` + +and/ or + + - :download:`text.utf8 <./text.utf8>` + - :download:`text.utf16 <./text.utf16>` + - :download:`text.utf32 <./text.utf32>` + +* write some of the text from the first exercise to file -- read that + file back in. + +.. nextslide:: Some Help + +.. rst-class:: left + +Reference: http://inamidst.com/stuff/unidata/ + +NOTE: if your terminal does not support unicode -- you'll get an error trying +to print. Try a different terminal or IDE, or google for a solution. + +Challenge Unicode LAB +---------------------- + +We saw this earlier + +.. code-block:: ipython + + In [38]: u'to \N{INFINITY} and beyond!'.decode('utf-8') + --------------------------------------------------------------------------- + UnicodeEncodeError Traceback (most recent call last) + in () + ----> 1 u'to \N{INFINITY} and beyond!'.decode('utf-8') + + /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.pyc in decode(input, errors) + 14 + 15 def decode(input, errors='strict'): + ---> 16 return codecs.utf_8_decode(input, errors, True) + 17 + 18 class IncrementalEncoder(codecs.IncrementalEncoder): + + UnicodeEncodeError: 'ascii' codec can't encode character u'\u221e' in position 3: ordinal not in range(128) + +.. nextslide:: + +But why would you **decode** a unicode object? + +And it should be a no-op -- why the exception? + +And why 'ascii'? I specified 'utf-8'! + +It's there for backward compatibility + +What's happening under the hood: + +.. code-block:: python + + u'to \N{INFINITY} and beyond!'.encode().decode('utf-8') + +It encodes with the default encoding (ascii), then decodes + +In this case, it barfs on attempting to encode to 'ascii' + +.. nextslide:: + +So never call decode on a unicode object! + +But what if someone passes one into a function of yours that's expecting +a py2 string? + +Type checking and converting -- yeach! + +Read: + +http://axialcorps.com/2014/03/20/unicode-str/ + +See if you can figure out the decorators: + +:download:`unicodify.py <./unicodify.py>`. + + +(This is advanced Python JuJu: Aren't you glad I didn't ask you to write +that yourself?) + diff --git a/slides_sources/source/supplements/unicode.rst b/_sources/supplements/unicode2.txt similarity index 79% rename from slides_sources/source/supplements/unicode.rst rename to _sources/supplements/unicode2.txt index 4e34ce6c..c44dff21 100644 --- a/slides_sources/source/supplements/unicode.rst +++ b/_sources/supplements/unicode2.txt @@ -1,17 +1,36 @@ +Antoher verison os the Unicode discussion -- I htink there is a bit in here that we'll want to use. -.. _unicode_supplement: -=================== -Unicode in Python 2 -=================== +======== +Unicode +======== + +.. rst-class:: left + + I hope you all read this: + + The Absolute Minimum Every Software Developer Absolutely, + Positively Must Know About Unicode and Character Sets (No Excuses!) + + http://www.joelonsoftware.com/articles/Unicode.html + + If not -- go read it! -A quick run-down of Unicode, its use in Python 2, and some of the gotchas that arise. +Fact number 1: +-------------- + +.. rst-class:: centered medium + + Everything is made up of bytes - - Chris Barker +If it's on disk or transmitted over a network, it's bytes + +Python provides some abstractions to make it easier to deal with bytes + +Unicode is a biggie -History -======= +Actually, dealing with numbers rather than bytes is big -- but we take that for granted What the heck is Unicode anyway? @@ -27,57 +46,54 @@ What the heck is Unicode anyway? * But each vendor used the top half (127-255) for different things. - * MacRoman, Windows 1252, etc... + * macroman, Windows 1252, etc... * There is now "latin-1", but still a lot of old files around -* Non-Western European languages required totally incompatible 1-byte encodings +* Non Western-European languages required totally incompatible 1-byte + encodings * No way to mix languages with different alphabets. - -Enter Unicode +Fact number 2: -------------- -The Unicode idea is pretty simple: -* one "code point" for all characters in all languages +.. rst-class:: centered medium -But how do you express that in bytes? - * Early days: we can fit all the code points in a two byte integer (65536 characters) + The world needs more than 255 charactors. - * Turns out that didn't work -- now need 32 bit integer to hold all of unicode "raw" (UTC-4) +.. rst-class:: centered -Enter "encodings": - * An encoding is a way to map specific bytes to a code point. - - * Each code point can have one or more bytes. + Hello, world! • Здравствуй, мир! + Բարեւ, աշխարհի! • !مرحبا ، العالم -Unicode --------- + !שלום, עולם • 여보세요 세계! -A good start: + नमस्ते, दुनिया! • 你好,世界! -The Absolute Minimum Every Software Developer Absolutely, -Positively Must Know About Unicode and Character Sets (No Excuses!) - -http://www.joelonsoftware.com/articles/Unicode.html +Enter Unicode +-------------- -.. nextslide:: +The Unicode idea is pretty simple: -**Everything is Bytes** + * one "code point" for all characters in all languages -* If it's on disk or on a network, it's bytes +But how do you express that in bytes? + * Early days: we can fit all the code points in a two byte integer (65536 characters) -* Python provides some abstractions to make it easier to deal with bytes + * Turns out that didn't work -- we now need 32 bit integer to hold all of unicode + "raw" (UTC-4) -- well we dopnt need that many, but common machines don't have + 24 bit integers. -Unicode is a biggie +Enter "encodings": + * An encoding is a way to map specific bytes to a code point. -(actually, dealing with numbers rather than bytes is big -- but we take that -for granted) + * Each code point can have one or more bytes. +========= Mechanics ========= @@ -89,14 +105,14 @@ Py2 strings are sequences of bytes Unicode strings are sequences of platonic characters It's almost one code point per character -- but there are complications -with combined characters: accents, etc. +with combined characters: accents, etc. (we can ignore those most of the time) Platonic characters cannot be written to disk or network! (ANSI: one character == one byte -- so easy!) -Strings vs unicode +str vs unicode ------------------- Python 2 has two types that let you work with text: @@ -118,7 +134,7 @@ And two ways to work with binary data: In [86]: str is bytes Out[86]: True -``bytes`` is there for py3 compatibility - -but it's good for making your +``bytes`` is there for py3 compatibility -- but it's good for making your intentions clear, too. @@ -236,7 +252,7 @@ Python 2.6 and above have a nice feature to make it easier to use unicode everyw from __future__ import unicode_literals After running that line, the ``u''`` is assumed - + .. code-block:: ipython In [1]: s = "this is a regular py2 string" @@ -265,7 +281,7 @@ But only a couple you are likely to need: * utf-8 (``*nix``) * utf-16 (Windows) -and of course, still the one-bytes ones. +And of course, still the one-bytes ones. * ASCII * Latin-1 @@ -294,7 +310,7 @@ UTF-16 Kind of like UTF-8, except it uses at least 16bits (2 bytes) for each character: not ASCII compatible. -But is still needs more than two bytes for some code points, so you still can't process +But it still needs more than two bytes for some code points, so you still can't assume two byte per character. In C/C++ held in a "wide char" or "wide string". @@ -308,11 +324,13 @@ There is a lot of criticism on the net about UTF-16 -- it's kind of the worst of * You can't assume every character is the same number of bytes * It takes up more memory than UTF-8 -`UTF Considered Harmful `_ +`UTF-16 Considered Harmful `_ But to be fair: -Early versions of Unicode: everything fit into two bytes (65536 code points). MS and Java were fairly early adopters, and it seemed simple enough to just use 2 bytes per character. +Early versions of Unicode: everything fit into two bytes (65536 code points). + +MS and Java were fairly early adopters, and it seemed simple enough to just use 2 bytes per character. When it turned out that 4 bytes were really needed, they were kind of stuck in the middle. @@ -353,8 +371,8 @@ http://docs.python.org/howto/unicode.html .. code-block:: python - import codecs - f = codecs.open('unicode.rst', encoding='utf-8') + import io + f = io.open('hello_unicode.py', encoding='utf-8') for line in f: print repr(line) @@ -388,9 +406,9 @@ But: some more obscure calls don't support unicode filenames: .. nextslide:: Exception messages: - + * Py2 Exceptions use str when they print messages. - + * But what if you pass in a unicode object? * It is encoded with the default encoding. @@ -399,7 +417,7 @@ Exception messages: NOPE: it swallows it instead. -:download:`exception_test.py <./exception_test.py>`. +:download:`unicode_exception_test.py <./unicode_exception_test.py>`. Unicode in Python 3 ---------------------- @@ -420,11 +438,11 @@ It's all much cleaner. (by the way, the recent implementations are very efficient...) -Exercises -========= - +================= Basic Unicode LAB -------------------- +================= + +.. rst-class left * Find some nifty non-ascii characters you might use. @@ -442,11 +460,14 @@ and/ or - :download:`text.utf16 <./text.utf16>` - :download:`text.utf32 <./text.utf32>` -* write some of the text from the first exercise to file -- read that file back in. +* write some of the text from the first exercise to file -- read that + file back in. .. nextslide:: Some Help -reference: http://inamidst.com/stuff/unidata/ +.. rst-class:: left + +Reference: http://inamidst.com/stuff/unidata/ NOTE: if your terminal does not support unicode -- you'll get an error trying to print. Try a different terminal or IDE, or google for a solution. @@ -465,10 +486,10 @@ We saw this earlier ----> 1 u'to \N{INFINITY} and beyond!'.decode('utf-8') /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.pyc in decode(input, errors) - 14 + 14 15 def decode(input, errors='strict'): ---> 16 return codecs.utf_8_decode(input, errors, True) - 17 + 17 18 class IncrementalEncoder(codecs.IncrementalEncoder): UnicodeEncodeError: 'ascii' codec can't encode character u'\u221e' in position 3: ordinal not in range(128) @@ -483,7 +504,7 @@ And why 'ascii'? I specified 'utf-8'! It's there for backward compatibility -What's happening under the hood +What's happening under the hood: .. code-block:: python @@ -497,7 +518,8 @@ In this case, it barfs on attempting to encode to 'ascii' So never call decode on a unicode object! -But what if someone passes one into a function of yours that's expecting a py2 string? +But what if someone passes one into a function of yours that's expecting +a py2 string? Type checking and converting -- yeach! @@ -510,5 +532,6 @@ See if you can figure out the decorators: :download:`unicodify.py <./unicodify.py>`. -(This is advanced Python JuJu: Aren't you glad I didn't ask you to write that yourself?) +(This is advanced Python JuJu: Aren't you glad I didn't ask you to write +that yourself?) diff --git a/slides_sources/source/supplements/virtualenv.rst b/_sources/supplements/virtualenv.txt similarity index 91% rename from slides_sources/source/supplements/virtualenv.rst rename to _sources/supplements/virtualenv.txt index fa371460..2b11489e 100644 --- a/slides_sources/source/supplements/virtualenv.rst +++ b/_sources/supplements/virtualenv.txt @@ -1,26 +1,33 @@ +.. _virtualenv_section: + *********************** Working with Virtualenv *********************** -"For every non-standard package installed in a system Python, the gods kill a -kitten" - me +.. rst-class:: medium + + "For every non-standard package installed in a system Python, the gods kill a + kitten" + - me +============ Reasons Why -=========== +============ +.. rst-class:: left -* As a working developer you will need to install packages that aren't in the - Python standard Library -* As a working developer you often need to install *different* versions of the - *same* library for different projects -* Conflicts arising from having the wrong version of a dependency installed can - cause long-term nightmares -* Use `virtualenv`_ ... -* **Always** + * As a working developer you will need to install packages that aren't in the + Python standard Library + * As a working developer you often need to install *different* versions of the + *same* library for different projects + * Conflicts arising from having the wrong version of a dependency installed can + cause long-term nightmares + * Use `virtualenv`_ ... + * **Always** Installing Virtualenv -===================== +--------------------- The best way is to install directly in your system Python (one exception to the rule). @@ -57,7 +64,7 @@ command available to you from your shell: $ virtualenv --help Usage: virtualenv [OPTIONS] DEST_DIR - + Options: --version show program's version number and exit -h, --help ... @@ -66,24 +73,27 @@ command available to you from your shell: .. _pip: http://www.pip-installer.org .. _the instructions here: http://www.pip-installer.org/en/latest/installing.html -Using Virtuelenv +================ +Using Virtualenv ================ -Creating a new virtualenv is very very simple: +.. rst-class:: left -.. code-block:: bash + Creating a new virtualenv is very very simple: - $ virtualenv [options] + .. code-block:: bash + $ virtualenv [options] -```` is just the name of the environment you want to create. It's -arbitrary. Let's make one for demonstration purposes: -.. code-block:: bash + ```` is just the name of the environment you want to create. It's + arbitrary. Let's make one for demonstration purposes: - $ virtualenv demoenv - New python executable in demoenv/bin/python - Installing setuptools, pip...done. + .. code-block:: bash + + $ virtualenv demoenv + New python executable in demoenv/bin/python + Installing setuptools, pip...done. What Happened? -------------- diff --git a/_sources/unused_stuff.txt b/_sources/unused_stuff.txt new file mode 100644 index 00000000..4343c76b --- /dev/null +++ b/_sources/unused_stuff.txt @@ -0,0 +1,32 @@ +.. stuff to put somewhere... + +switch? +-------- + +Many languages have a ``switch`` construct: + +.. code-block:: js + + switch (expr) { + case "Oranges": + document.write("Oranges are $0.59 a pound.
        "); + break; + case "Apples": + document.write("Apples are $0.32 a pound.
        "); + break; + case "Mangoes": + case "Papayas": + document.write("Mangoes and papayas are $2.79 a pound.
        "); + break; + default: + document.write("Sorry, we are out of " + expr + ".
        "); + } + +.. nextslide:: + +**Not Python** + +use ``if..elif..elif..else`` + +(or a dictionary, or subclassing....) + diff --git a/_static/ajax-loader.gif b/_static/ajax-loader.gif new file mode 100644 index 00000000..61faf8ca Binary files /dev/null and b/_static/ajax-loader.gif differ diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..2b513f0c --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,604 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/color_git_prompt.png b/_static/color_git_prompt.png new file mode 100644 index 00000000..b85ab440 Binary files /dev/null and b/_static/color_git_prompt.png differ diff --git a/_static/comment-bright.png b/_static/comment-bright.png new file mode 100644 index 00000000..551517b8 Binary files /dev/null and b/_static/comment-bright.png differ diff --git a/_static/comment-close.png b/_static/comment-close.png new file mode 100644 index 00000000..09b54be4 Binary files /dev/null and b/_static/comment-close.png differ diff --git a/_static/comment.png b/_static/comment.png new file mode 100644 index 00000000..92feb52b Binary files /dev/null and b/_static/comment.png differ diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 00000000..7e17fb14 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1,2 @@ +.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}} +/*# sourceMappingURL=badge_only.css.map */ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 00000000..7be93399 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,5 @@ +*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:0.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all 0.3s ease-in;-moz-transition:all 0.3s ease-in;transition:all 0.3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 0.3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.35765%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:0.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:0.34375em 0.625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:0.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:0.5em 0.625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{width:36px;height:12px;margin:12px 0;position:relative;border-radius:4px;background:#ccc;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:before{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:after{content:"false";position:absolute;left:48px;display:block;font-size:12px;color:#ccc}.wy-switch.active{background:#1e8449}.wy-switch.active:before{left:24px;background:#27AE60}.wy-switch.active:after{content:"true"}.wy-switch.disabled,.wy-switch.active.disabled{cursor:not-allowed}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:0.5em 0.625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9B59B6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],pre.literal-block div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}@media print{.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#EAF2F5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#555;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:0.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:0.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:0.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:0.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:0.4045em 5.663em;border-top:none;border-bottom:none}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:0.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:0.4045em 1.618em;display:block;position:relative;font-size:90%;color:#b3b3b3}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#b3b3b3}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:0.809em;margin-bottom:0.809em;z-index:200;background-color:#2980B9;text-align:center;padding:0.809em;display:block;color:#fcfcfc;margin-bottom:0.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto 0.809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:0.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:0.85em}.wy-side-nav-search>div.version{margin-top:-0.4045em;margin-bottom:0.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:0.4045em 0.809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:#999}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}.rst-content img{max-width:100%;height:auto !important}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after{visibility:visible;content:"";font-family:FontAwesome;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content .toctree-wrapper p.caption:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink,.rst-content p.caption:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list td>strong{display:inline-block;margin-top:3px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt,.rst-content tt,.rst-content code{color:#000;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:400;src:local("Inconsolata"),local("Inconsolata-Regular"),url(../fonts/Inconsolata-Regular.ttf) format("truetype")}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:700;src:local("Inconsolata Bold"),local("Inconsolata-Bold"),url(../fonts/Inconsolata-Bold.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:400;src:local("Lato Regular"),local("Lato-Regular"),url(../fonts/Lato-Regular.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:700;src:local("Lato Bold"),local("Lato-Bold"),url(../fonts/Lato-Bold.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:local("Roboto Slab Regular"),local("RobotoSlab-Regular"),url(../fonts/RobotoSlab-Regular.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:local("Roboto Slab Bold"),local("RobotoSlab-Bold"),url(../fonts/RobotoSlab-Bold.ttf) format("truetype")} +/*# sourceMappingURL=theme.css.map */ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..81634956 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,287 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/_static/down-pressed.png b/_static/down-pressed.png new file mode 100644 index 00000000..7c30d004 Binary files /dev/null and b/_static/down-pressed.png differ diff --git a/_static/down.png b/_static/down.png new file mode 100644 index 00000000..f48098a4 Binary files /dev/null and b/_static/down.png differ diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..254c60bf Binary files /dev/null and b/_static/file.png differ diff --git a/_static/flake8_output.png b/_static/flake8_output.png new file mode 100644 index 00000000..dc44e48e Binary files /dev/null and b/_static/flake8_output.png differ diff --git a/_static/fonts/Inconsolata-Bold.ttf b/_static/fonts/Inconsolata-Bold.ttf new file mode 100644 index 00000000..58c9fef3 Binary files /dev/null and b/_static/fonts/Inconsolata-Bold.ttf differ diff --git a/_static/fonts/Inconsolata-Regular.ttf b/_static/fonts/Inconsolata-Regular.ttf new file mode 100644 index 00000000..a87ffba6 Binary files /dev/null and b/_static/fonts/Inconsolata-Regular.ttf differ diff --git a/_static/fonts/Lato-Bold.ttf b/_static/fonts/Lato-Bold.ttf new file mode 100644 index 00000000..74343694 Binary files /dev/null and b/_static/fonts/Lato-Bold.ttf differ diff --git a/_static/fonts/Lato-Regular.ttf b/_static/fonts/Lato-Regular.ttf new file mode 100644 index 00000000..04ea8efb Binary files /dev/null and b/_static/fonts/Lato-Regular.ttf differ diff --git a/_static/fonts/RobotoSlab-Bold.ttf b/_static/fonts/RobotoSlab-Bold.ttf new file mode 100644 index 00000000..df5d1df2 Binary files /dev/null and b/_static/fonts/RobotoSlab-Bold.ttf differ diff --git a/_static/fonts/RobotoSlab-Regular.ttf b/_static/fonts/RobotoSlab-Regular.ttf new file mode 100644 index 00000000..eb52a790 Binary files /dev/null and b/_static/fonts/RobotoSlab-Regular.ttf differ diff --git a/_static/fonts/fontawesome-webfont.eot b/_static/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..84677bc0 Binary files /dev/null and b/_static/fonts/fontawesome-webfont.eot differ diff --git a/_static/fonts/fontawesome-webfont.svg b/_static/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..d907b25a --- /dev/null +++ b/_static/fonts/fontawesome-webfont.svg @@ -0,0 +1,520 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_static/fonts/fontawesome-webfont.ttf b/_static/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..96a3639c Binary files /dev/null and b/_static/fonts/fontawesome-webfont.ttf differ diff --git a/_static/fonts/fontawesome-webfont.woff b/_static/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..628b6a52 Binary files /dev/null and b/_static/fonts/fontawesome-webfont.woff differ diff --git a/_static/git_another_commit_on_branch.png b/_static/git_another_commit_on_branch.png new file mode 100644 index 00000000..7ef6a068 Binary files /dev/null and b/_static/git_another_commit_on_branch.png differ diff --git a/_static/git_checkout_branch.png b/_static/git_checkout_branch.png new file mode 100644 index 00000000..dab12bdc Binary files /dev/null and b/_static/git_checkout_branch.png differ diff --git a/_static/git_checkout_master.png b/_static/git_checkout_master.png new file mode 100644 index 00000000..dc245a7f Binary files /dev/null and b/_static/git_checkout_master.png differ diff --git a/_static/git_commit_on_branch.png b/_static/git_commit_on_branch.png new file mode 100644 index 00000000..23143d7f Binary files /dev/null and b/_static/git_commit_on_branch.png differ diff --git a/_static/git_head.png b/_static/git_head.png new file mode 100644 index 00000000..c48c40e6 Binary files /dev/null and b/_static/git_head.png differ diff --git a/_static/git_master_branch.png b/_static/git_master_branch.png new file mode 100644 index 00000000..9c4aeb8a Binary files /dev/null and b/_static/git_master_branch.png differ diff --git a/_static/git_merge_commit.png b/_static/git_merge_commit.png new file mode 100644 index 00000000..2df3d2d3 Binary files /dev/null and b/_static/git_merge_commit.png differ diff --git a/_static/git_new_branch.png b/_static/git_new_branch.png new file mode 100644 index 00000000..a0a4ef4c Binary files /dev/null and b/_static/git_new_branch.png differ diff --git a/_static/git_new_commit.png b/_static/git_new_commit.png new file mode 100644 index 00000000..012eb847 Binary files /dev/null and b/_static/git_new_commit.png differ diff --git a/_static/git_new_commit_on_master.png b/_static/git_new_commit_on_master.png new file mode 100644 index 00000000..6c25e51a Binary files /dev/null and b/_static/git_new_commit_on_master.png differ diff --git a/_static/git_simple_timeline.png b/_static/git_simple_timeline.png new file mode 100644 index 00000000..465f546c Binary files /dev/null and b/_static/git_simple_timeline.png differ diff --git a/_static/jquery-1.11.1.js b/_static/jquery-1.11.1.js new file mode 100644 index 00000000..d4b67f7e --- /dev/null +++ b/_static/jquery-1.11.1.js @@ -0,0 +1,10308 @@ +/*! + * jQuery JavaScript Library v1.11.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-05-01T17:42Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper window is present, + // execute the factory and get jQuery + // For environments that do not inherently posses a window with a document + // (such as Node.js), expose a jQuery-making factory as module.exports + // This accentuates the need for the creation of a real window + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +// + +var deletedIds = []; + +var slice = deletedIds.slice; + +var concat = deletedIds.concat; + +var push = deletedIds.push; + +var indexOf = deletedIds.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + version = "1.11.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android<4.1, IE<9 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: deletedIds.sort, + splice: deletedIds.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( support.ownLast ) { + for ( key in obj ) { + return hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call(obj) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Support: Android<4.1, IE<9 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( indexOf ) { + return indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + while ( j < len ) { + first[ i++ ] = second[ j++ ]; + } + + // Support: IE<9 + // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) + if ( len !== len ) { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: function() { + return +( new Date() ); + }, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v1.10.19 + * http://sizzlejs.com/ + * + * Copyright 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-04-18 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + characterEncoding + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( documentIsHTML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document (jQuery #6963) + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== strundefined && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, + doc = node ? node.ownerDocument || node : preferredDoc, + parent = doc.defaultView; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsHTML = !isXML( doc ); + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent !== parent.top ) { + // IE11 does not have attachEvent, so all must suffer + if ( parent.addEventListener ) { + parent.addEventListener( "unload", function() { + setDocument(); + }, false ); + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", function() { + setDocument(); + }); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if getElementsByClassName can be trusted + support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { + div.innerHTML = "
        "; + + // Support: Safari<4 + // Catch class over-caching + div.firstChild.className = "i"; + // Support: Opera<10 + // Catch gEBCN failure to find non-leading classes + return div.getElementsByClassName("i").length === 2; + }); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowclip^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (oldCache = outerCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + outerCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context !== document && context; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is no seed and only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome<14 +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; + }); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +}); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof rootjQuery.ready !== "undefined" ? + rootjQuery.ready( selector ) : + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.extend({ + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +jQuery.fn.extend({ + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.unique( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.unique( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +}); +var rnotwhite = (/\S+/g); + + + +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + + } else if ( !(--remaining) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend({ + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +}); + +/** + * Clean-up method for dom ready events + */ +function detach() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } +} + +/** + * The ready event handler and self cleanup method + */ +function completed() { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + + +var strundefined = typeof undefined; + + + +// Support: IE<9 +// Iteration over object's inherited properties before its own +var i; +for ( i in jQuery( support ) ) { + break; +} +support.ownLast = i !== "0"; + +// Note: most support tests are defined in their respective modules. +// false until the test is run +support.inlineBlockNeedsLayout = false; + +// Execute ASAP in case we need to set body.style.zoom +jQuery(function() { + // Minified: var a,b,c,d + var val, div, body, container; + + body = document.getElementsByTagName( "body" )[ 0 ]; + if ( !body || !body.style ) { + // Return for frameset docs that don't have a body + return; + } + + // Setup + div = document.createElement( "div" ); + container = document.createElement( "div" ); + container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; + body.appendChild( container ).appendChild( div ); + + if ( typeof div.style.zoom !== strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; + + support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; + if ( val ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); +}); + + + + +(function() { + var div = document.createElement( "div" ); + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +/** + * Determines whether an object can have data + */ +jQuery.acceptData = function( elem ) { + var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], + nodeType = +elem.nodeType || 1; + + // Do not set data on non-element DOM nodes because it will not be cleared (#8335). + return nodeType !== 1 && nodeType !== 9 ? + false : + + // Nodes accept data unless otherwise specified; rejection can be conditional + !noData || noData !== true && elem.getAttribute("classid") === noData; +}; + + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + +function internalData( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // The following elements (space-suffixed to avoid Object.prototype collisions) + // throw uncatchable exceptions if you attempt to set expando properties + noData: { + "applet ": true, + "embed ": true, + // ...but Flash objects (which have this classid) *can* handle expandos + "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var i, name, data, + elem = this[0], + attrs = elem && elem.attributes; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return arguments.length > 1 ? + + // Sets one value + this.each(function() { + jQuery.data( this, key, value ); + }) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + + +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; +}; +var rcheckableType = (/^(?:checkbox|radio)$/i); + + + +(function() { + // Minified: var a,b,c + var input = document.createElement( "input" ), + div = document.createElement( "div" ), + fragment = document.createDocumentFragment(); + + // Setup + div.innerHTML = "
        a"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName( "tbody" ).length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = + document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + input.type = "checkbox"; + input.checked = true; + fragment.appendChild( input ); + support.appendChecked = input.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE6-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // #11217 - WebKit loses check when the name is after the checked attribute + fragment.appendChild( div ); + div.innerHTML = ""; + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + support.noCloneEvent = true; + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } +})(); + + +(function() { + var i, eventName, + div = document.createElement( "div" ); + + // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) + for ( i in { submit: true, change: true, focusin: true }) { + eventName = "on" + i; + + if ( !(support[ i + "Bubbles" ] = eventName in window) ) { + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + div.setAttribute( eventName, "t" ); + support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && jQuery.acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + // Support: IE < 9, Android < 4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + jQuery._removeData( doc, fix ); + } else { + jQuery._data( doc, fix, attaches ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
        ", "
        " ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
        " ], + tr: [ 2, "", "
        " ], + col: [ 2, "", "
        " ], + td: [ 3, "", "
        " ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
        ", "
        " ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!support.noCloneEvent || !support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
        " && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + deletedIds.push( id ); + } + } + } + } + } +}); + +jQuery.fn.extend({ + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + remove: function( selector, keepData /* Internal Use Only */ ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map(function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var arg = arguments[ 0 ]; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + arg = this.parentNode; + + jQuery.cleanData( getAll( this ) ); + + if ( arg ) { + arg.replaceChild( elem, this ); + } + }); + + // Force removal if there was no new content (e.g., from empty arguments) + return arg && (arg.length || arg.nodeType) ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, self.html() ); + } + self.domManip( args, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[i], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + + +var iframe, + elemdisplay = {}; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var style, + elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + // getDefaultComputedStyle might be reliably used only on attached element + display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? + + // Use of this method is a temporary fix (more like optmization) until something better comes along, + // since it was removed from specification and supported only in FF + style.display : jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = (iframe || jQuery( " - \ No newline at end of file diff --git a/slides_sources/old_versions/week-04/homework/trigram_solution.py b/slides_sources/old_versions/week-04/homework/trigram_solution.py deleted file mode 100644 index fb2759f3..00000000 --- a/slides_sources/old_versions/week-04/homework/trigram_solution.py +++ /dev/null @@ -1,82 +0,0 @@ -#/usr/bin/ev python - -""" -Trigram.py - -A solution to the trigram coding Kata: - -http://codekata.pragprog.com/2007/01/kata_fourteen_t.html - -Chris Barker's Solution -""" - -# infilename = "sherlock_small.txt" -infilename = "sherlock.txt" - -import string -import random - -# translation table for string.translate: -# I use this to purge the punctuation.. - -# stuff I want to keep: -valid = string.letters + "'" # keep the contractions -all = ''.join([chr(i) for i in range(256)]) -table = [] -for c in all: - if c in valid: - table.append(c) - else: - table.append(' ') -table = ''.join(table) - -infile = open(infilename, 'r') -# strip out the header, table of contents, etc. -for i in range(61): - infile.readline() -# read the rest of the file into memory -in_data = infile.read() - -# Dictionary for trigram results: -# The keys will be all the word pairs -# The values will be a list of the words that follow each pair -word_pairs = {} - -# lower-case everything to remove that complication: -in_data = in_data.lower() - -# strip out the punctuation: -in_data = in_data.translate(table) - -# split into words -words = in_data.split() - -# remove the bare single quotes -# " ' " is both a quote and an apostrophe -words = [word for word in words if word != "'"] # loop through the words -for i in range(len(words) - 2): - pair = " ".join(words[i:i+2]) - follower = words[i+2] - # setdefault() returns the value if pair is already in the dict - # if it's not, it adds it, setting the value to a an empty list - # then it returns the list, which we then append the following - # word to. - word_pairs.setdefault(pair,[]).append(follower) - - -# A little reporting -#for pair, followers in word_pairs.items(): -# if len(followers) > 1: -# print pair, followers - -# create some new text -new_text = [] -for i in range (100): # do 100 sets. - pair = random.sample(word_pairs, 1)[0] - follower = random.sample(word_pairs[pair], 1)[0] - new_text.extend( (pair, follower) ) - -new_text = " ".join(new_text) - -print new_text - diff --git a/slides_sources/old_versions/week-04/presentation-week-04.pdf b/slides_sources/old_versions/week-04/presentation-week-04.pdf deleted file mode 100644 index 0e8034c2..00000000 Binary files a/slides_sources/old_versions/week-04/presentation-week-04.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-04/presentation-week-04.tex b/slides_sources/old_versions/week-04/presentation-week-04.tex deleted file mode 100644 index 53fe1d30..00000000 --- a/slides_sources/old_versions/week-04/presentation-week-04.tex +++ /dev/null @@ -1,1062 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Intro to Python: Week 4]{Introduction to Python:\\ Dictionaries, Sets, Exceptions\\ Files and Text Processing} -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{October 22, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - - -\section{Review/Questions} - -% --------------------------------------------- -\begin{frame}{Review of Previous Class} - -\begin{itemize} - \item Sequences - \item Lists - \item Tuples -\end{itemize} - -\vfill -{\Large Any questions?} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning talks today:} - -\vfill -{\Large ( Jo-Anne Antoun )} - -\vfill -{\Large - Sako Eaton - -\vfill -Brandon Ivers - -\vfill -Gary Pei - -\vfill -Nathan Savage - -} -\vfill - -\end{frame} - - -% -------------------------------------------- -\begin{frame}[fragile]{Notes on Workflow} - - \vfill - {\Large For more than a few lines:} - - \vfill - {\large Write your code in a module} - - \vfill - {\large Have a way to re-run quickly} - \begin{itemize} - \item Plain command line: \verb|$ python my_script.py| - \item iPython: \verb|run my_script.py| - \item The ``run'' button / keystroke in your IDE. - \end{itemize} - - \vfill - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Finish Last Class...} - - \vfill - {\Large More on Looping} - - \vfill - {\Large Strings!} - - \vfill - -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -\vfill -{\Large -Jo-Anne Antoun - -} -\vfill - -\end{frame} - - -% ################################## -\section{Dictionaries and Sets} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary} - -{\Large Python calls it a \verb|dict| } - -\vfill -{\Large Other languages call it:} -\begin{itemize} - \item dictionary - \item associative array - \item map - \item hash table - \item hash - \item key-value pair -\end{itemize} - -\vfill - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Constructors} - -\begin{verbatim} ->>> {'key1': 3, 'key2': 5} -{'key1': 3, 'key2': 5} - ->>> dict([('key1', 3),('key2', 5)]) -{'key1': 3, 'key2': 5} - ->>> dict(key1=3, key2= 5) -{'key1': 3, 'key2': 5} - ->>> d = {} ->>> d['key1'] = 3 ->>> d['key2'] = 5 ->>> d -{'key1': 3, 'key2': 5} -\end{verbatim} -% {\Large Which to use depends on the shape of your data} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Indexing} - -\begin{verbatim} ->>> d = {'name': 'Brian', 'score': 42} ->>> d['score'] -42 ->>> d = {1: 'one', 0: 'zero'} ->>> d[0] -'zero' ->>> d['non-existing key'] -Traceback (most recent call last): - File "", line 1, in -KeyError: 'non-existing key' -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Indexing} - -{\Large Keys can be any immutable:} -\begin{itemize} - \item numbers - \item string - \item tuples -\end{itemize} - -\begin{verbatim} -In [325]: d[3] = 'string' -In [326]: d[3.14] = 'pi' -In [327]: d['pi'] = 3.14 -In [328]: d[ (1,2,3) ] = 'a tuple key' -In [329]: d[ [1,2,3] ] = 'a list key' - TypeError: unhashable type: 'list' -\end{verbatim} - -\vfill -Actually -- any "hashable" type. -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Indexing} - -\vfill -{\Large hash functions convert arbitrarily large data to a small proxy (usually int) - -\vfill -always return the same proxy for the same input - -\vfill -MD5, SHA, etc -\vfill -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Indexing} - -\vfill -{\Large -Dictionaries hash the key to an integer proxy and use it to find the key and value -} -\vfill -{\Large -Key lookup is efficient because the hash function leads directly to a bucket with a very few keys (often just one) -} -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Indexing} - -\vfill -{\Large -What would happen if the proxy changed after storing a key? -} -\vfill -{\Large -Hashability requires immutability} -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Indexing} - -\vfill -{\Large - -Key lookup is very efficient - -\vfill -Same average time regardless of size -} - -\vfill -also... Python name look-ups are implemented with dict: - - --- its highly optimized -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Indexing} - -\vfill -{\Large -{\center - -key to value - -lookup is one way - -}} -\vfill -{\Large -{\center - -value to key - -requires visiting the whole dict - -}} - -\vfill -{\Large -if you need to check dict values often, create another dict or set (up to you to keep them in sync) - -} -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Ordering (not)} - -\vfill -{\Large -dictionaries have no defined order -} -\vfill -\begin{verbatim} -In [352]: d = {'one':1, 'two':2, 'three':3} - -In [353]: d -Out[353]: {'one': 1, 'three': 3, 'two': 2} - -In [354]: d.keys() -Out[354]: ['three', 'two', 'one'] -\end{verbatim} -\vfill -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Dictionary Iterating} - -{\Large \verb|for| iterates the keys} -\vfill -\begin{verbatim} ->>> d = {'name': 'Brian', 'score': 42} ->>> for x in d: -... print x -... -score name -\end{verbatim} -\vfill -{note the different order...} -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{dict keys and values} - -\vfill -\begin{verbatim} ->>> d.keys() -['score', 'name'] - ->>> d.values() -[42, 'Brian'] - ->>> d.items() -[('score', 42), ('name', 'Brian')] -\end{verbatim} -\vfill -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{dict keys and values} - -{\Large iterating on everything} -\vfill -\begin{verbatim} ->>> d = {'name': 'Brian', 'score': 42} ->>> for k, v in d.items(): -... print "%s: %s" % (k, v) -... -score: 42 -name: Brian -\end{verbatim} -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Dictionary Performance } - -\begin{itemize} - \item indexing is fast and constant time: O(1) - \item x in s cpnstant time: O(1) - \item visiting all is proportional to n: O(n) - \item inserting is constant time: O(1) - \item deleting is constant time: O(1) -\end{itemize} - -\vfill -\url{ http://wiki.python.org/moin/TimeComplexity} - -\end{frame} - - - -% --------------------------------------------- -\begin{frame}[fragile]{ Sets } - -\vfill -{\Large \verb|set| is an unordered collection of distinct values} - -\vfill -{\Large Essentially a dict with only keys} - -\vfill - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Set Constructors} - -\vfill -\begin{verbatim} ->>> set() -set([]) ->>> set([1, 2, 3]) -set([1, 2, 3]) -# as of 2.7 ->>> {1, 2, 3} -set([1, 2, 3]) ->>> s = set() ->>> s.update([1, 2, 3]) ->>> s -set([1, 2, 3]) -\end{verbatim} -\vfill - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{ Set Properties} - -\vfill -{\Large \verb|Set| members must be hashable} - -\vfill -{\Large Like dictionary keys -- and for same reason (efficient lookup)} - -\vfill -{\Large No indexing (unordered) } - -\vfill -\begin{verbatim} ->>> s[1] -Traceback (most recent call last): - File "", line 1, in -TypeError: 'set' object does not support indexing -\end{verbatim} - -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{ Set Methods} - -\begin{verbatim} ->> s = set([1]) ->>> s.pop() # an arbitrary member -1 ->>> s.pop() -Traceback (most recent call last): - File "", line 1, in -KeyError: 'pop from an empty set' - ->>> s = set([1, 2, 3]) ->>> s.remove(2) ->>> s.remove(2) -Traceback (most recent call last): - File "", line 1, in -KeyError: 2 -\end{verbatim} - -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{ Set Methods} - -\begin{verbatim} -s.isdisjoint(other) - -s.issubset(other) - -s.union(other, ...) - -s.intersection(other, ...) - -s.difference(other, ...) - -s.symmetric_difference( other, ...) -\end{verbatim} - -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{ Frozen Set} - -\vfill -{\Large Also \verb|frozenset|} - -\vfill -{\Large immutable -- for use as a key in a dict\\ -(or another set...)} - -\vfill -\begin{verbatim} ->>> fs = frozenset((3,8,5)) ->>> fs.add(9) -Traceback (most recent call last): - File "", line 1, in -AttributeError: 'frozenset' object has no attribute 'add' -\end{verbatim} - -\vfill -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\Large Dictionary LAB:} - -\vfill -{\large \verb|code/dict_lab.html (rst) |} - -\vfill -\end{frame} - - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -\vfill -{\Large - Sako Eaton - -\vfill -Brandon Ivers -} -\vfill - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Exceptions} - -%----------------------------------- -\begin{frame}[fragile]{Exceptions} - -{\Large Another Branching structure:} -\vfill -\begin{verbatim} -try: - do_something() - f = open('missing.txt') - process(f) # never called if file missing -except IOError: - print "couldn't open missing.txt" -\end{verbatim} -\vfill -\end{frame} - -\begin{frame}[fragile]{Exceptions} - -{\Large Never Do this:} -\vfill -\begin{verbatim} -try: - do_something() - f = open('missing.txt') - process(f) # never called if file missing -except: - print "couldn't open missing.txt" -\end{verbatim} -\vfill -\end{frame} - -\begin{frame}[fragile]{Exceptions} - -{\Large Use Exceptions, rather than your own tests - - \hspace{0.1in} -- Don't do this:} - -\vfill -\begin{verbatim} -do_something() -if os.path.exists('missing.txt'): - f = open('missing.txt') - process(f) # never called if file missing -\end{verbatim} -\vfill -it will almost always work -- but the almost will drive you crazy -\end{frame} - - -\begin{frame}[fragile]{Exceptions} - -{\centering - -{\Large "easier to ask forgiveness than permission" -\vfill -\hfill -- Grace Hopper -} -} - -\vfill -\url{http://www.youtube.com/watch?v=AZDWveIdqjY} - -(Pycon talk by Alex Martelli) -\end{frame} - - -\begin{frame}[fragile]{Exceptions} - -\vfill -{\Large -For simple scripts, let exceptions happen\\ -\vfill - -Only handle the exception if the code can and will do something about it -} -\vfill -(much better debugging info when an error does occur) -\end{frame} - - -\begin{frame}[fragile]{Exceptions -- finally } - -\vfill -\begin{verbatim} -try: - do_something() - f = open('missing.txt') - process(f) # never called if file missing -except IOError: - print "couldn't open missing.txt" -finally: - do_some_clean-up -\end{verbatim} -\vfill -{\Large the \verb|finally:| clause will always run} -\end{frame} - -\begin{frame}[fragile]{Exceptions -- else } - -\vfill -\begin{verbatim} -try: - do_something() - f = open('missing.txt') -except IOError: - print "couldn't open missing.txt" -else: - process(f) # only called if there was no exception -\end{verbatim} -\vfill -{\Large Advantage: - -you know where the Exception came from} -\end{frame} - -%-------------------------------------------- -\begin{frame}[fragile]{Exceptions -- using them } - -\vfill -\begin{verbatim} -try: - do_something() - f = open('missing.txt') -except IOError as the_error: - print the_error - the_error.extra_info = "some more information" - raise -\end{verbatim} - -{\Large Particularly useful if you catch more than one exception:} - -\begin{verbatim} -except (IOError, BufferError, OSError) as the_error: - do_something_with (the_error) -\end{verbatim} - -\end{frame} - - -\begin{frame}[fragile]{Raising Exceptions } - -\begin{verbatim} -def divide(a,b): - if b == 0: - raise ZeroDivisionError("b can not be zero") - else: - return a / b -\end{verbatim} -\vfill -{\Large when you call it: } -\vfill -\begin{verbatim} -In [515]: divide (12,0) - -ZeroDivisionError: b can not be zero -\end{verbatim} - -\end{frame} - - - -\begin{frame}[fragile]{Built in Exceptions} - -{\Large You can create your own custom exceptions} - -{\Large But...} - -\begin{verbatim} -exp = \ - [name for name in dir(__builtin__) if "Error" in name] - -len(exp) -32 -\end{verbatim} - -{\Large For the most part, you can/should use a built in one} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large Exceptions Lab: Improving \verb|raw_input|:} - -{\large -\vfill -The \verb|raw_input()| function can generate two exceptions: -\verb|EOFError| or \verb|KeyboardInterrupt| on end-of-file -(EOF) or canceled input. - -\vfill -Create a wrapper function, perhaps \verb|safe_input()| that returns -\verb|None| rather rather than raising these exceptions, when -the user enters \verb|^C| for Keyboard Interrupt, or \verb|^D| -(\verb|^Z| on Windows) for End Of File. -} - -\vfill -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -{\Large -\vfill -Gary Pei - -\vfill -Nathan Savage -} -\vfill - -\end{frame} - -\section{File Reading and Writing} - -%------------------------------- -\begin{frame}[fragile]{Files} - -{\Large Text Files} - -\begin{verbatim} -f = open('secrets.txt') -secret_data = f.read() -f.close() -\end{verbatim} - -{\Large \verb|secret_data| is a string} - -\vfill -(can also use \verb|file()| -- \verb|open()| is preferred) -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Files} - -{\Large Binary Files} - -\begin{verbatim} -f = open('secrets.txt', 'rb') -secret_data = f.read() -f.close() -\end{verbatim} - -{\Large \verb|secret_data| is still a string \\[.1in] -(with arbitrary bytes in it)} -\vfill -(See the \verb|struct| module to unpack binary data ) -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Files} - -{\Large File Opening Modes} -\vfill -\begin{verbatim} -f = open('secrets.txt', [mode]) - -'r', 'w', 'a' -'rb', 'wb', 'ab' -r+, w+, a+ -r+b, w+b, a+b -U -U+ -\end{verbatim} -\vfill -{\Large Gotcha -- w mode always clears the file} -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Text File Notes} - -{\Large Text is default} -\begin{itemize} - \item Newlines are translated: \verb|\r\n -> \n| - \item -- reading and writing! - \item Use *nux-style in your code: \verb|\n| - \item Open text files with \verb|'U'| "Universal" flag -\end{itemize} - -\vfill -{\Large Gotcha:} -\begin{itemize} - \item no difference between text and binary on *nix\\ - \begin{itemize} - \item breaks on Windows - \end{itemize} -\end{itemize} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{File Reading} - -{\Large Reading Part of a file} - -\begin{verbatim} -header_size = 4096 - -f = open('secrets.txt') -secret_data = f.read(header_size) -f.close() -\end{verbatim} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{File Reading} - -{\Large Common Idioms} - -\begin{verbatim} -for line in open('secrets.txt'): - print line -\end{verbatim} - -\begin{verbatim} -f = open('secrets.txt') -while True: - line = f.readline() - if not line: - break - do_something_with_line() -\end{verbatim} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{File Writing} - -\begin{verbatim} - -outfile = open('output.txt', 'w') - -for i in range(10): - outfile.write("this is line: %i\n"%i) - -\end{verbatim} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{File Methods} - -{\Large Commonly Used Methods} -\begin{verbatim} - -f.read() f.readline() f.readlines() - -f.write(str) f.writelines(seq) - -f.seek(offset) f.tell() - -f.flush() - -f.close() -\end{verbatim} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{File Like Objects} - -{\Large File-like objects } -\vfill -{\large Many classes implement the file interface:} -\vfill -\begin{itemize} - \item loggers - \item \verb|sys.stdout| - \item \verb|urllib.open()| - \item pipes, subprocesses - \item StringIO -\end{itemize} - -\url{http://docs.python.org/library/stdtypes.html#bltin-­‐file-­‐objects} -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{StringIO} - -{\Large StringIO } -\vfill -\begin{verbatim} -In [417]: import StringIO -In [420]: f = StringIO.StringIO() - -In [421]: f.write("somestuff") - -In [422]: f.seek(0) - -In [423]: f.read() -Out[423]: 'somestuff' -\end{verbatim} - -{\Large handy for testing} -\end{frame} - - -\section{Paths and Directories} - -% ---------------------------------- -\begin{frame}[fragile]{Paths} - -{\Large Relative paths:} - -\begin{verbatim} -secret.txt -./secret.txt -\end{verbatim} - -{\Large Absolute paths:} -\begin{verbatim} -/home/chris/secret.txt -\end{verbatim} - -{\Large Either work with \verb|open()|, etc.} - -\vfill -(working directory only makes sense with command-line programs...) -\end{frame} - -% ---------------------------------- -\begin{frame}[fragile]{os.path} - -\begin{verbatim} -os.getcwd() -- os.getcwdu() -chdir(path) - -os.path.abspath() -os.path.relpath() -\end{verbatim} - -\end{frame} - -% ---------------------------------- -\begin{frame}[fragile]{os.path} - -\vfill -\begin{verbatim} -os.path.split() -os.path.splitext() -os.path.basename() -os.path.dirname() -os.path.join() -\end{verbatim} - -\vfill -(all platform independent) - -\end{frame} - - -% ---------------------------------- -\begin{frame}[fragile]{directories} - -\vfill -\begin{verbatim} -os.listdir() -os.mkdir() - -os.walk() - -\end{verbatim} - -\vfill -(higher level stuff in \verb|shutil| module) - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large Paths and File Processing} - -\begin{itemize} - \item write a program which prints the full path to all files - in the current directory, one per line - \item write a program which copies a file from a source, to a - destination (without using shutil, or the OS copy command) - \item write a program that extracts all the programming languages that the students in this class used before (\verb|code\students_languages.txt|) - \item update mail-merge from the earlier lab to write output - to individual files on disk -\end{itemize} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{Homework} - -{\large Recommended Reading} -\begin{itemize} - \item Dive Into Python: Chapt. 13,14 - \item Unicode: \url{http://www.joelonsoftware.com/articles/Unicode.html} -\end{itemize} - -\vfill -{\large Do the Labs you didn't finish in class} - -\vfill -\begin{itemize} - \item Coding Kata 14 - Dave Thomas \\ - \url{http://codekata.pragprog.com/2007/01/ kata_fourteen_t.html} - - \item Use The Adventures of Sherlock Holmes as input:\\ - \verb|code/sherlock.txt| (ascii) - - \item This is intentionally open-ended and underspecified. There are many interesting decisions to make. - - \item Experiment with different lengths for the lookup key. (3 words, 4 words, 3 letters, etc) -\end{itemize} - -\end{frame} - - -\end{document} - - diff --git a/slides_sources/old_versions/week-05/code/codingbat.py b/slides_sources/old_versions/week-05/code/codingbat.py deleted file mode 100644 index 2bb34ebf..00000000 --- a/slides_sources/old_versions/week-05/code/codingbat.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python - -""" -Examples from: http://codingbat.com - -Put here so we can write unit tests for them ourselves -""" - -# Python > Warmup-1 > sleep_in - -def sleep_in(weekday, vacation): - return not (weekday == True and vacation == False) - - diff --git a/slides_sources/old_versions/week-05/code/codingbat_unittest.py b/slides_sources/old_versions/week-05/code/codingbat_unittest.py deleted file mode 100755 index c242e267..00000000 --- a/slides_sources/old_versions/week-05/code/codingbat_unittest.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python - -""" -test file for codingbat module - -This version used unittest -""" - -import unittest -from codingbat import sleep_in - -class Test_sleep_in(unittest.TestCase): - - def test_false_false(self): - self.assertTrue( sleep_in(False, False) ) - - def test_true_false(self): - self.assertFalse( sleep_in(True, False) ) - - def test_false_true(self): - self.assertTrue( sleep_in(False, True) ) - - def test_true_true(self): - self.assertTrue( sleep_in(True, True) ) - -if __name__ == "__main__": - unittest.main() - - \ No newline at end of file diff --git a/slides_sources/old_versions/week-05/code/comprehension.html b/slides_sources/old_versions/week-05/code/comprehension.html deleted file mode 100644 index 1ec91a23..00000000 --- a/slides_sources/old_versions/week-05/code/comprehension.html +++ /dev/null @@ -1,510 +0,0 @@ - - - - - - - - - - -
        - - -
        -

        1. Creating lists with list comprehensions

        -
        -
        ->>> feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals',
        -                        'fruit bats']
        -
        -
        ->>> comprehension = [delicacy.capitalize() for delicacy in feast]
        -
        -
        -
        -

        What is the output of:

        -
        -
        ->>> comprehension[0]
        -???
        -
        -
        ->>> comprehension[2]
        -???
        -
        -
        -
        -
        -
        -

        2. Filtering lists with list comprehensions

        -
        -
        ->>> feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals',
        -            'fruit bats']
        -
        -
        ->>> comprehension = [delicacy for delicacy in feast if len(delicacy) > 6]
        -
        -
        -
        -

        What is the output of:

        -
        -
        ->>> len(feast)
        -???
        -
        -
        ->>> len(comprehension)
        -???
        -
        -
        -
        -
        -
        -

        3. Unpacking tuples in list comprehensions

        -
        -
        ->>> list_of_tuples = [(1, 'lumberjack'), (2, 'inquisition'), (4, 'spam')]
        -
        -
        ->>> comprehension = [ skit * number for number, skit in list_of_tuples ]
        -
        -
        -
        -

        What is the output of:

        -
        -
        ->>> comprehension[0]
        -???
        -
        -
        ->>> len(comprehension[2])
        -???
        -
        -
        -
        -
        -
        -

        4. Double list comprehension

        -
        -
        ->>> list_of_eggs = ['poached egg', 'fried egg']
        -
        -
        ->>> list_of_meats = ['lite spam', 'ham spam', 'fried spam']
        -
        -
        ->>> comprehension = [ '{0} and {1}'.format(egg, meat) for egg in list_of_eggs for meat in list_of_meats]
        -
        -
        -
        -

        What is the output of:

        -
        -
        ->>> len(comprehension)
        -???
        -
        -
        ->>> comprehension[0]
        -
        -
        -
        -
        -
        -

        5. Creating a set with set comprehension

        -
        -
        ->>> comprehension = { x for x in 'aabbbcccc'}
        -
        -
        -
        -

        What is the output of:

        -
        -
        ->>> comprehension
        -???
        -
        -
        -
        -
        -
        -

        6. Creating a dictionary with dictionary comprehension

        -
        -
        ->>> dict_of_weapons = {'first': 'fear', 'second': 'surprise',
        -            'third':'ruthless efficiency', 'forth':'fanatical devotion',
        -            'fifth': None}
        -
        -
        ->>> dict_comprehension = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon}
        -
        -
        -
        -

        What is the output of:

        -
        ->>> 'first' in dict_comprehension
        -        ???
        -
        -
        -
        ->>> 'FIRST' in dict_comprehension
        -???
        -
        -
        ->>> len(dict_of_weapons)
        -???
        -
        -
        ->>> len(dict_comprehension)
        -???
        -
        -
        -

        See also: https://github.com/gregmalcolm/python_koans -https://github.com/gregmalcolm/python_koans/blob/master/python2/koans/about_comprehension.py

        -
        -
        -
        -

        7. Count even numbers

        -

        This is from CodingBat "count_evens" (http://codingbat.com/prob/p189616)

        -

        Using list comprehension, return the number of even ints in the given array. Note: the % "mod" operator computes the remainder, e.g. 5 % 2 is 1.

        -
        -

        count_evens([2, 1, 2, 3, 4]) → 3

        -

        count_evens([2, 2, 0]) → 3

        -

        count_evens([1, 3, 5]) → 0

        -

        def count_evens(nums):

        -
        -
        -
        - - diff --git a/slides_sources/old_versions/week-05/code/comprehension.rst b/slides_sources/old_versions/week-05/code/comprehension.rst deleted file mode 100644 index 418430a8..00000000 --- a/slides_sources/old_versions/week-05/code/comprehension.rst +++ /dev/null @@ -1,112 +0,0 @@ -1. Creating lists with list comprehensions -========================================== - >>> feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals', - 'fruit bats'] - - >>> comprehension = [delicacy.capitalize() for delicacy in feast] - -What is the output of: ----------------------- - >>> comprehension[0] - ??? - - >>> comprehension[2] - ??? - -2. Filtering lists with list comprehensions -=========================================== - >>> feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals', - 'fruit bats'] - - >>> comprehension = [delicacy for delicacy in feast if len(delicacy) > 6] - -What is the output of: ----------------------- - >>> len(feast) - ??? - - >>> len(comprehension) - ??? - - -3. Unpacking tuples in list comprehensions -========================================== - >>> list_of_tuples = [(1, 'lumberjack'), (2, 'inquisition'), (4, 'spam')] - - >>> comprehension = [ skit * number for number, skit in list_of_tuples ] - -What is the output of: ----------------------- - >>> comprehension[0] - ??? - - >>> len(comprehension[2]) - ??? - -4. Double list comprehension -============================ - >>> list_of_eggs = ['poached egg', 'fried egg'] - - >>> list_of_meats = ['lite spam', 'ham spam', 'fried spam'] - - >>> comprehension = [ '{0} and {1}'.format(egg, meat) for egg in list_of_eggs for meat in list_of_meats] - -What is the output of: ----------------------- - >>> len(comprehension) - ??? - - >>> comprehension[0] - -5. Creating a set with set comprehension -======================================== - >>> comprehension = { x for x in 'aabbbcccc'} - -What is the output of: ----------------------- - - >>> comprehension - ??? - -6. Creating a dictionary with dictionary comprehension -====================================================== - >>> dict_of_weapons = {'first': 'fear', 'second': 'surprise', - 'third':'ruthless efficiency', 'forth':'fanatical devotion', - 'fifth': None} - - >>> dict_comprehension = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} - -What is the output of: ----------------------- ->>> 'first' in dict_comprehension - ??? - - >>> 'FIRST' in dict_comprehension - ??? - - >>> len(dict_of_weapons) - ??? - - >>> len(dict_comprehension) - ??? - - -See also: https://github.com/gregmalcolm/python_koans -https://github.com/gregmalcolm/python_koans/blob/master/python2/koans/about_comprehension.py - - -7. Count even numbers -===================== -This is from CodingBat "count_evens" (http://codingbat.com/prob/p189616) - -*Using list comprehension*, return the number of even ints in the given array. Note: the % "mod" operator computes the remainder, e.g. 5 % 2 is 1. - - count_evens([2, 1, 2, 3, 4]) → 3 - - count_evens([2, 2, 0]) → 3 - - count_evens([1, 3, 5]) → 0 - - - def count_evens(nums): - diff --git a/slides_sources/old_versions/week-05/code/test_codingbat.py b/slides_sources/old_versions/week-05/code/test_codingbat.py deleted file mode 100755 index 4923ebf1..00000000 --- a/slides_sources/old_versions/week-05/code/test_codingbat.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -""" -test file for codingbat module - -This version can be run with nose or py.test -""" - -from codingbat import sleep_in - -def test_false_false(): - assert sleep_in(False, False) - -def test_true_false(): - assert not ( sleep_in(True, False) ) - -def test_false_true(): - assert sleep_in(False, True) - -def test_true_true(): - assert sleep_in(True, True) - - \ No newline at end of file diff --git a/slides_sources/old_versions/week-05/code/test_pytest_parameter.py b/slides_sources/old_versions/week-05/code/test_pytest_parameter.py deleted file mode 100644 index 52449af3..00000000 --- a/slides_sources/old_versions/week-05/code/test_pytest_parameter.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -""" -pytest example of a parameterized test - -NOTE: there is a failure in here! can you fix it? - -""" -import pytest - -# a (really simple) function to test -def add(a, b): - """ - returns the sum of a and b - """ - return a + b - -# now some test data: - -test_data = [ ( ( 2, 3), 5), - ( (-3, 2), -1), - ( ( 2, 0.5), 2.5), - ( ( "this", "that"), "this that"), - ( ( [1,2,3], [6,7,8]), [1,2,3,6,7,8]), - ] - -@pytest.mark.parametrize(("input", "result"), test_data) -def test_add(input, result): - assert add(*input) == result - diff --git a/slides_sources/old_versions/week-05/code/test_random_nose.py b/slides_sources/old_versions/week-05/code/test_random_nose.py deleted file mode 100644 index 9e0fb4e3..00000000 --- a/slides_sources/old_versions/week-05/code/test_random_nose.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python - -""" -port of the random unit tests from the python docs to nose/py.test -""" - -import random -import nose.tools - -seq = range(10) - -def test_shuffle(): - # make sure the shuffled sequence does not lose any elements - random.shuffle(seq) - seq.sort() - print seq - assert seq == range(8) - -@nose.tools.raises(TypeError) -def test_shuffle_immutable(): - # should raise an exception for an immutable sequence - random.shuffle( (1,2,3) ) - -def test_choice(): - element = random.choice(seq) - assert (element in seq) - -def test_sample(): - for element in random.sample(seq, 5): - assert element in seq - -@nose.tools.raises(ValueError) -def test_sample_too_large(): - random.sample(seq, 20) diff --git a/slides_sources/old_versions/week-05/code/test_random_pytest.py b/slides_sources/old_versions/week-05/code/test_random_pytest.py deleted file mode 100644 index 5576cc7f..00000000 --- a/slides_sources/old_versions/week-05/code/test_random_pytest.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python - -""" -port of the random unit tests from the python docs to nose/py.test -""" - -import random -import pytest - - -seq = range(10) - -def test_shuffle(): - # make sure the shuffled sequence does not lose any elements - random.shuffle(seq) - seq.sort() - print "seq:", seq - ## expect this to fail -- so we can see the output. - assert seq == range(10) - -def test_shuffle_immutable(): - pytest.raises(TypeError, random.shuffle, (1,2,3) ) - -def test_choice(): - element = random.choice(seq) - assert (element in seq) - -def test_sample(): - for element in random.sample(seq, 5): - assert element in seq - -def test_sample_too_large(): - with pytest.raises(ValueError): - random.sample(seq, 20) diff --git a/slides_sources/old_versions/week-05/code/text.utf16 b/slides_sources/old_versions/week-05/code/text.utf16 deleted file mode 100644 index f2fd8040..00000000 Binary files a/slides_sources/old_versions/week-05/code/text.utf16 and /dev/null differ diff --git a/slides_sources/old_versions/week-05/code/text.utf32 b/slides_sources/old_versions/week-05/code/text.utf32 deleted file mode 100644 index a713e3e0..00000000 Binary files a/slides_sources/old_versions/week-05/code/text.utf32 and /dev/null differ diff --git a/slides_sources/old_versions/week-05/code/unittest_example.py b/slides_sources/old_versions/week-05/code/unittest_example.py deleted file mode 100644 index 6458e6ce..00000000 --- a/slides_sources/old_versions/week-05/code/unittest_example.py +++ /dev/null @@ -1,29 +0,0 @@ -import random -import unittest - -class TestSequenceFunctions(unittest.TestCase): - - def setUp(self): - self.seq = range(10) - - def test_shuffle(self): - # make sure the shuffled sequence does not lose any elements - random.shuffle(self.seq) - self.seq.sort() - self.assertEqual(self.seq, range(10)) - - # should raise an exception for an immutable sequence - self.assertRaises(TypeError, random.shuffle, (1,2,3) ) - - def test_choice(self): - element = random.choice(self.seq) - self.assertTrue(element in self.seq) - - def test_sample(self): - with self.assertRaises(ValueError): - random.sample(self.seq, 20) - for element in random.sample(self.seq, 5): - self.assertTrue(element in self.seq) - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/slides_sources/old_versions/week-05/presentation-week-05.aux b/slides_sources/old_versions/week-05/presentation-week-05.aux deleted file mode 100644 index fb7173de..00000000 --- a/slides_sources/old_versions/week-05/presentation-week-05.aux +++ /dev/null @@ -1,147 +0,0 @@ -\relax -\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} -\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined -\global\let\oldcontentsline\contentsline -\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} -\global\let\oldnewlabel\newlabel -\gdef\newlabel#1#2{\newlabelxx{#1}#2} -\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} -\AtEndDocument{\ifx\hyper@anchor\@undefined -\let\contentsline\oldcontentsline -\let\newlabel\oldnewlabel -\fi} -\fi} -\global\let\hyper@last\relax -\gdef\HyperFirstAtBeginDocument#1{#1} -\providecommand\HyField@AuxAddToFields[1]{} -\@writefile{toc}{\beamer@endinputifotherversion {3.10pt}} -\@writefile{nav}{\beamer@endinputifotherversion {3.10pt}} -\@writefile{nav}{\headcommand {\slideentry {0}{0}{1}{1/1}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {1}{1}}} -\@writefile{nav}{\headcommand {\slideentry {0}{0}{2}{2/2}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {2}{2}}} -\@writefile{toc}{\beamer@sectionintoc {1}{Review/Questions}{3}{0}{1}} -\@writefile{nav}{\headcommand {\sectionentry {1}{Review/Questions}{3}{Review/Questions}{0}}} -\@writefile{nav}{\headcommand {\beamer@sectionpages {1}{2}}} -\@writefile{nav}{\headcommand {\beamer@subsectionpages {1}{2}}} -\@writefile{nav}{\headcommand {\slideentry {1}{0}{3}{3/3}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {3}{3}}} -\@writefile{nav}{\headcommand {\slideentry {1}{0}{4}{4/4}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {4}{4}}} -\@writefile{nav}{\headcommand {\slideentry {1}{0}{5}{5/5}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {5}{5}}} -\@writefile{toc}{\beamer@sectionintoc {2}{Unicode}{6}{0}{2}} -\@writefile{nav}{\headcommand {\sectionentry {2}{Unicode}{6}{Unicode}{0}}} -\@writefile{nav}{\headcommand {\beamer@sectionpages {3}{5}}} -\@writefile{nav}{\headcommand {\beamer@subsectionpages {3}{5}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{6}{6/6}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {6}{6}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{7}{7/7}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {7}{7}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{8}{8/8}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {8}{8}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{9}{9/9}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {9}{9}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{10}{10/10}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {10}{10}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{11}{11/11}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {11}{11}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{12}{12/12}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {12}{12}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{13}{13/13}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {13}{13}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{14}{14/14}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {14}{14}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{15}{15/15}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {15}{15}}} -\@writefile{nav}{\headcommand {\slideentry {2}{0}{16}{16/16}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {16}{16}}} -\@writefile{toc}{\beamer@sectionintoc {3}{Advanced Argument Passing}{17}{0}{3}} -\@writefile{nav}{\headcommand {\sectionentry {3}{Advanced Argument Passing}{17}{Advanced Argument Passing}{0}}} -\@writefile{nav}{\headcommand {\beamer@sectionpages {6}{16}}} -\@writefile{nav}{\headcommand {\beamer@subsectionpages {6}{16}}} -\@writefile{nav}{\headcommand {\slideentry {3}{0}{17}{17/17}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {17}{17}}} -\@writefile{nav}{\headcommand {\slideentry {3}{0}{18}{18/18}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {18}{18}}} -\@writefile{nav}{\headcommand {\slideentry {3}{0}{19}{19/19}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {19}{19}}} -\@writefile{nav}{\headcommand {\slideentry {3}{0}{20}{20/20}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {20}{20}}} -\@writefile{nav}{\headcommand {\slideentry {3}{0}{21}{21/21}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {21}{21}}} -\@writefile{nav}{\headcommand {\slideentry {3}{0}{22}{22/22}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {22}{22}}} -\@writefile{nav}{\headcommand {\slideentry {3}{0}{23}{23/23}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {23}{23}}} -\@writefile{toc}{\beamer@sectionintoc {4}{List and Dict Comprehensions}{24}{0}{4}} -\@writefile{nav}{\headcommand {\sectionentry {4}{List and Dict Comprehensions}{24}{List and Dict Comprehensions}{0}}} -\@writefile{nav}{\headcommand {\beamer@sectionpages {17}{23}}} -\@writefile{nav}{\headcommand {\beamer@subsectionpages {17}{23}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{24}{24/24}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {24}{24}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{25}{25/25}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {25}{25}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{26}{26/26}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {26}{26}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{27}{27/27}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {27}{27}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{28}{28/28}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {28}{28}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{29}{29/29}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {29}{29}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{30}{30/30}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {30}{30}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{31}{31/31}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {31}{31}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{32}{32/32}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {32}{32}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{33}{33/33}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {33}{33}}} -\@writefile{nav}{\headcommand {\slideentry {4}{0}{34}{34/34}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {34}{34}}} -\@writefile{toc}{\beamer@sectionintoc {5}{Unit Testing}{35}{0}{5}} -\@writefile{nav}{\headcommand {\sectionentry {5}{Unit Testing}{35}{Unit Testing}{0}}} -\@writefile{nav}{\headcommand {\beamer@sectionpages {24}{34}}} -\@writefile{nav}{\headcommand {\beamer@subsectionpages {24}{34}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{35}{35/35}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {35}{35}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{36}{36/36}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {36}{36}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{37}{37/37}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {37}{37}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{38}{38/38}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {38}{38}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{39}{39/39}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {39}{39}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{40}{40/40}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {40}{40}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{41}{41/41}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {41}{41}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{42}{42/42}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {42}{42}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{43}{43/43}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {43}{43}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{44}{44/44}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {44}{44}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{45}{45/45}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {45}{45}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{46}{46/46}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {46}{46}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{47}{47/47}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {47}{47}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{48}{48/48}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {48}{48}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{49}{49/49}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {49}{49}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{50}{50/50}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {50}{50}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{51}{51/51}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {51}{51}}} -\@writefile{nav}{\headcommand {\slideentry {5}{0}{52}{52/52}{}{0}}} -\@writefile{nav}{\headcommand {\beamer@framepages {52}{52}}} -\@writefile{nav}{\headcommand {\beamer@partpages {1}{52}}} -\@writefile{nav}{\headcommand {\beamer@subsectionpages {35}{52}}} -\@writefile{nav}{\headcommand {\beamer@sectionpages {35}{52}}} -\@writefile{nav}{\headcommand {\beamer@documentpages {52}}} -\@writefile{nav}{\headcommand {\def \inserttotalframenumber {52}}} diff --git a/slides_sources/old_versions/week-05/presentation-week-05.log b/slides_sources/old_versions/week-05/presentation-week-05.log deleted file mode 100644 index c14318ad..00000000 --- a/slides_sources/old_versions/week-05/presentation-week-05.log +++ /dev/null @@ -1,1311 +0,0 @@ -This is pdfTeX, Version 3.1415926-2.3-1.40.12 (TeX Live 2011) (format=pdflatex 2011.7.3) 29 OCT 2013 17:46 -entering extended mode - restricted \write18 enabled. - %&-line parsing enabled. -**presentation-week-05 -(./presentation-week-05.tex -LaTeX2e <2009/09/24> -Babel and hyphenation patterns for english, dumylang, nohyphenation, ge -rman-x-2009-06-19, ngerman-x-2009-06-19, afrikaans, ancientgreek, ibycus, arabi -c, armenian, basque, bulgarian, catalan, pinyin, coptic, croatian, czech, danis -h, dutch, ukenglish, usenglishmax, esperanto, estonian, ethiopic, farsi, finnis -h, french, galician, german, ngerman, swissgerman, monogreek, greek, hungarian, - icelandic, assamese, bengali, gujarati, hindi, kannada, malayalam, marathi, or -iya, panjabi, tamil, telugu, indonesian, interlingua, irish, italian, kurmanji, - lao, latin, latvian, lithuanian, mongolian, mongolianlmc, bokmal, nynorsk, pol -ish, portuguese, romanian, russian, sanskrit, serbian, serbianc, slovak, sloven -ian, spanish, swedish, turkish, turkmen, ukrainian, uppersorbian, welsh, loaded -. -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamer.cls -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasercs.sty -Package: beamerbasercs 2010/06/12 (rcs-revision c3821710bb40) -) -Document Class: beamer 2010/06/21 development version 3.10 A class for typesett -ing presentations (rcs-revision a6b1a8434d30) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasemodes.sty -Package: beamerbasemodes 2010/05/01 (rcs-revision efa082c6111d) -\beamer@tempbox=\box26 -\beamer@tempcount=\count79 -\c@beamerpauses=\count80 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasedecode.sty -Package: beamerbasedecode 2010/05/01 (rcs-revision efa082c6111d) -\beamer@slideinframe=\count81 -\beamer@minimum=\count82 -) -\beamer@commentbox=\box27 -\beamer@modecount=\count83 -) -\headheight=\dimen102 -\headdp=\dimen103 -\footheight=\dimen104 -\sidebarheight=\dimen105 -\beamer@tempdim=\dimen106 -\beamer@finalheight=\dimen107 -\beamer@animht=\dimen108 -\beamer@animdp=\dimen109 -\beamer@animwd=\dimen110 -\beamer@leftmargin=\dimen111 -\beamer@rightmargin=\dimen112 -\beamer@leftsidebar=\dimen113 -\beamer@rightsidebar=\dimen114 -\beamer@boxsize=\dimen115 -\beamer@vboxoffset=\dimen116 -\beamer@descdefault=\dimen117 -\beamer@descriptionwidth=\dimen118 -\beamer@lastskip=\skip41 -\beamer@areabox=\box28 -\beamer@animcurrent=\box29 -\beamer@animshowbox=\box30 -\beamer@sectionbox=\box31 -\beamer@logobox=\box32 -\beamer@linebox=\box33 -\beamer@sectioncount=\count84 -\beamer@subsubsectionmax=\count85 -\beamer@subsectionmax=\count86 -\beamer@sectionmax=\count87 -\beamer@totalheads=\count88 -\beamer@headcounter=\count89 -\beamer@partstartpage=\count90 -\beamer@sectionstartpage=\count91 -\beamer@subsectionstartpage=\count92 -\beamer@animationtempa=\count93 -\beamer@animationtempb=\count94 -\beamer@xpos=\count95 -\beamer@ypos=\count96 -\beamer@showpartnumber=\count97 -\beamer@currentsubsection=\count98 -\beamer@coveringdepth=\count99 -\beamer@sectionadjust=\count100 -\beamer@tocsectionnumber=\count101 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseoptions.sty -Package: beamerbaseoptions 2010/04/27 (rcs-revision 982469101dd6) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/graphics/keyval.sty -Package: keyval 1999/03/16 v1.13 key=value parser (DPC) -\KV@toks@=\toks14 -)) -\beamer@paperwidth=\skip42 -\beamer@paperheight=\skip43 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/geometry/geometry.sty -Package: geometry 2010/09/12 v5.6 Page Geometry - -(/usr/local/texlive/2011/texmf-dist/tex/generic/oberdiek/ifpdf.sty -Package: ifpdf 2011/01/30 v2.3 Provides the ifpdf switch (HO) -Package ifpdf Info: pdfTeX in PDF mode is detected. -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/oberdiek/ifvtex.sty -Package: ifvtex 2010/03/01 v1.5 Switches for detecting VTeX and its modes (HO) -Package ifvtex Info: VTeX not detected. -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/ifxetex/ifxetex.sty -Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional -) -\Gm@cnth=\count102 -\Gm@cntv=\count103 -\c@Gm@tempcnt=\count104 -\Gm@bindingoffset=\dimen119 -\Gm@wd@mp=\dimen120 -\Gm@odd@mp=\dimen121 -\Gm@even@mp=\dimen122 -\Gm@layoutwidth=\dimen123 -\Gm@layoutheight=\dimen124 -\Gm@layouthoffset=\dimen125 -\Gm@layoutvoffset=\dimen126 -\Gm@dimlist=\toks15 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/base/size11.clo -File: size11.clo 2007/10/19 v1.4h Standard LaTeX file (size option) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty -(/usr/local/texlive/2011/texmf-dist/tex/latex/graphics/graphicx.sty -Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/graphics/graphics.sty -Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/graphics/trig.sty -Package: trig 1999/03/16 v1.09 sin cos tan (DPC) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/latexconfig/graphics.cfg -File: graphics.cfg 2010/04/23 v1.9 graphics configuration of TeX Live -) -Package graphics Info: Driver file: pdftex.def on input line 91. - -(/usr/local/texlive/2011/texmf-dist/tex/latex/pdftex-def/pdftex.def -File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX - -(/usr/local/texlive/2011/texmf-dist/tex/generic/oberdiek/infwarerr.sty -Package: infwarerr 2010/04/08 v1.3 Providing info/warning/message (HO) -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/oberdiek/ltxcmds.sty -Package: ltxcmds 2011/04/18 v1.20 LaTeX kernel commands for general use (HO) -) -\Gread@gobject=\count105 -)) -\Gin@req@height=\dimen127 -\Gin@req@width=\dimen128 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty -(/usr/local/texlive/2011/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.te -x -\pgfutil@everybye=\toks16 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def -\pgfutil@abb=\box34 -(/usr/local/texlive/2011/texmf-dist/tex/latex/ms/everyshi.sty -Package: everyshi 2001/05/15 v3.00 EveryShipout Package (MS) -)) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex -Package: pgfrcs 2010/10/25 v2.10 (rcs-revision 1.24) -)) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex -Package: pgfsys 2010/06/30 v2.10 (rcs-revision 1.37) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex -\pgfkeys@pathtoks=\toks17 -\pgfkeys@temptoks=\toks18 - -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.c -ode.tex -\pgfkeys@tmptoks=\toks19 -)) -\pgf@x=\dimen129 -\pgf@y=\dimen130 -\pgf@xa=\dimen131 -\pgf@ya=\dimen132 -\pgf@xb=\dimen133 -\pgf@yb=\dimen134 -\pgf@xc=\dimen135 -\pgf@yc=\dimen136 -\w@pgf@writea=\write3 -\r@pgf@reada=\read1 -\c@pgf@counta=\count106 -\c@pgf@countb=\count107 -\c@pgf@countc=\count108 -\c@pgf@countd=\count109 - -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg -File: pgf.cfg 2008/05/14 (rcs-revision 1.7) -) -Package pgfsys Info: Driver file for pgf: pgfsys-pdftex.def on input line 900. - -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.d -ef -File: pgfsys-pdftex.def 2009/05/22 (rcs-revision 1.26) - -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-p -df.def -File: pgfsys-common-pdf.def 2008/05/19 (rcs-revision 1.10) -))) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath. -code.tex -File: pgfsyssoftpath.code.tex 2008/07/18 (rcs-revision 1.7) -\pgfsyssoftpath@smallbuffer@items=\count110 -\pgfsyssoftpath@bigbuffer@items=\count111 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol. -code.tex -File: pgfsysprotocol.code.tex 2006/10/16 (rcs-revision 1.4) -)) (/usr/local/texlive/2011/texmf-dist/tex/latex/xcolor/xcolor.sty -Package: xcolor 2007/01/21 v2.11 LaTeX color extensions (UK) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/latexconfig/color.cfg -File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive -) -Package xcolor Info: Driver file: pdftex.def on input line 225. -Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1337. -Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1341. -Package xcolor Info: Model `RGB' extended on input line 1353. -Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1355. -Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1356. -Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1357. -Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1358. -Package xcolor Info: Model `Gray' substituted by `gray' on input line 1359. -Package xcolor Info: Model `wave' substituted by `hsb' on input line 1360. -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex -Package: pgfcore 2010/04/11 v2.10 (rcs-revision 1.7) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex -\pgfmath@dimen=\dimen137 -\pgfmath@count=\count112 -\pgfmath@box=\box35 -\pgfmath@toks=\toks20 -\pgfmath@stack@operand=\toks21 -\pgfmath@stack@operation=\toks22 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code. -tex -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic -.code.tex) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigo -nometric.code.tex) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.rando -m.code.tex) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.compa -rison.code.tex) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base. -code.tex) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round -.code.tex) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc. -code.tex))) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex -\c@pgfmathroundto@lastzeros=\count113 -)) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.co -de.tex -File: pgfcorepoints.code.tex 2010/04/09 (rcs-revision 1.20) -\pgf@picminx=\dimen138 -\pgf@picmaxx=\dimen139 -\pgf@picminy=\dimen140 -\pgf@picmaxy=\dimen141 -\pgf@pathminx=\dimen142 -\pgf@pathmaxx=\dimen143 -\pgf@pathminy=\dimen144 -\pgf@pathmaxy=\dimen145 -\pgf@xx=\dimen146 -\pgf@xy=\dimen147 -\pgf@yx=\dimen148 -\pgf@yy=\dimen149 -\pgf@zx=\dimen150 -\pgf@zy=\dimen151 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconst -ruct.code.tex -File: pgfcorepathconstruct.code.tex 2010/08/03 (rcs-revision 1.24) -\pgf@path@lastx=\dimen152 -\pgf@path@lasty=\dimen153 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage -.code.tex -File: pgfcorepathusage.code.tex 2008/04/22 (rcs-revision 1.12) -\pgf@shorten@end@additional=\dimen154 -\pgf@shorten@start@additional=\dimen155 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.co -de.tex -File: pgfcorescopes.code.tex 2010/09/08 (rcs-revision 1.34) -\pgfpic=\box36 -\pgf@hbox=\box37 -\pgf@layerbox@main=\box38 -\pgf@picture@serial@count=\count114 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicst -ate.code.tex -File: pgfcoregraphicstate.code.tex 2008/04/22 (rcs-revision 1.9) -\pgflinewidth=\dimen156 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransform -ations.code.tex -File: pgfcoretransformations.code.tex 2009/06/10 (rcs-revision 1.11) -\pgf@pt@x=\dimen157 -\pgf@pt@y=\dimen158 -\pgf@pt@temp=\dimen159 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.cod -e.tex -File: pgfcorequick.code.tex 2008/10/09 (rcs-revision 1.3) -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.c -ode.tex -File: pgfcoreobjects.code.tex 2006/10/11 (rcs-revision 1.2) -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathproce -ssing.code.tex -File: pgfcorepathprocessing.code.tex 2008/10/09 (rcs-revision 1.8) -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.co -de.tex -File: pgfcorearrows.code.tex 2008/04/23 (rcs-revision 1.11) -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.cod -e.tex -File: pgfcoreshade.code.tex 2008/11/23 (rcs-revision 1.13) -\pgf@max=\dimen160 -\pgf@sys@shading@range@num=\count115 -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.cod -e.tex -File: pgfcoreimage.code.tex 2010/03/25 (rcs-revision 1.16) - -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal. -code.tex -File: pgfcoreexternal.code.tex 2010/09/01 (rcs-revision 1.17) -\pgfexternal@startupbox=\box39 -)) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.co -de.tex -File: pgfcorelayers.code.tex 2010/08/27 (rcs-revision 1.2) -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretranspare -ncy.code.tex -File: pgfcoretransparency.code.tex 2008/01/17 (rcs-revision 1.2) -) -(/usr/local/texlive/2011/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns. -code.tex -File: pgfcorepatterns.code.tex 2009/07/02 (rcs-revision 1.3) -))) -(/usr/local/texlive/2011/texmf-dist/tex/latex/pgf/utilities/xxcolor.sty -Package: xxcolor 2003/10/24 ver 0.1 -\XC@nummixins=\count116 -\XC@countmixins=\count117 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/hyperref/hyperref.sty -Package: hyperref 2011/04/17 v6.82g Hypertext links for LaTeX - -(/usr/local/texlive/2011/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty -Package: hobsub-hyperref 2011/04/23 v1.4 Bundle oberdiek, subset hyperref (HO) - -(/usr/local/texlive/2011/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty -Package: hobsub-generic 2011/04/23 v1.4 Bundle oberdiek, subset generic (HO) -Package: hobsub 2011/04/23 v1.4 Subsetting bundle oberdiek (HO) -Package hobsub Info: Skipping package `infwarerr' (already loaded). -Package hobsub Info: Skipping package `ltxcmds' (already loaded). -Package: ifluatex 2010/03/01 v1.3 Provides the ifluatex switch (HO) -Package ifluatex Info: LuaTeX not detected. -Package hobsub Info: Skipping package `ifvtex' (already loaded). -Package: intcalc 2007/09/27 v1.1 Expandable integer calculations (HO) -Package hobsub Info: Skipping package `ifpdf' (already loaded). -Package: etexcmds 2011/02/16 v1.5 Prefix for e-TeX command names (HO) -Package etexcmds Info: Could not find \expanded. -(etexcmds) That can mean that you are not using pdfTeX 1.50 or -(etexcmds) that some package has redefined \expanded. -(etexcmds) In the latter case, load this package earlier. -Package: kvsetkeys 2011/04/07 v1.13 Key value parser (HO) -Package: kvdefinekeys 2011/04/07 v1.3 Defining keys (HO) -Package: pdftexcmds 2011/04/22 v0.16 Utilities of pdfTeX for LuaTeX (HO) -Package pdftexcmds Info: LuaTeX not detected. -Package pdftexcmds Info: \pdf@primitive is available. -Package pdftexcmds Info: \pdf@ifprimitive is available. -Package pdftexcmds Info: \pdfdraftmode found. -Package: pdfescape 2011/04/04 v1.12 Provides string conversions (HO) -Package: bigintcalc 2011/01/30 v1.2 Expandable big integer calculations (HO) -Package: bitset 2011/01/30 v1.1 Data type bit set (HO) -Package: uniquecounter 2011/01/30 v1.2 Provides unlimited unique counter (HO) -) -Package hobsub Info: Skipping package `hobsub' (already loaded). -Package: letltxmacro 2010/09/02 v1.4 Let assignment for LaTeX macros (HO) -Package: hopatch 2011/01/30 v1.0 Wrapper for package hooks (HO) -Package: xcolor-patch 2011/01/30 xcolor patch -Package: atveryend 2011/04/23 v1.7 Hooks at very end of document (HO) -Package atveryend Info: \enddocument detected (standard). -Package: atbegshi 2011/01/30 v1.15 At begin shipout hook (HO) -Package: refcount 2010/12/01 v3.2 Data extraction from references (HO) -Package: hycolor 2011/01/30 v1.7 Color options of hyperref/bookmark (HO) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/oberdiek/kvoptions.sty -Package: kvoptions 2010/12/23 v3.10 Keyval support for LaTeX options (HO) -) -\@linkdim=\dimen161 -\Hy@linkcounter=\count118 -\Hy@pagecounter=\count119 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/hyperref/pd1enc.def -File: pd1enc.def 2011/04/17 v6.82g Hyperref: PDFDocEncoding definition (HO) -) -\Hy@SavedSpaceFactor=\count120 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/latexconfig/hyperref.cfg -File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive -) -Package hyperref Info: Option `bookmarks' set `true' on input line 3905. -Package hyperref Info: Option `bookmarksopen' set `true' on input line 3905. -Package hyperref Info: Option `implicit' set `false' on input line 3905. -Package hyperref Info: Hyper figures OFF on input line 4026. -Package hyperref Info: Link nesting OFF on input line 4031. -Package hyperref Info: Hyper index ON on input line 4034. -Package hyperref Info: Plain pages OFF on input line 4041. -Package hyperref Info: Backreferencing OFF on input line 4046. -Package hyperref Info: Implicit mode OFF; no redefinition of LaTeX internals. -Package hyperref Info: Bookmarks ON on input line 4264. -\c@Hy@tempcnt=\count121 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/url/url.sty -\Urlmuskip=\muskip10 -Package: url 2006/04/12 ver 3.3 Verb mode for urls, etc. -) -LaTeX Info: Redefining \url on input line 4617. -\Fld@menulength=\count122 -\Field@Width=\dimen162 -\Fld@charsize=\dimen163 -Package hyperref Info: Hyper figures OFF on input line 5701. -Package hyperref Info: Link nesting OFF on input line 5706. -Package hyperref Info: Hyper index ON on input line 5709. -Package hyperref Info: backreferencing OFF on input line 5716. -Package hyperref Info: Link coloring OFF on input line 5721. -Package hyperref Info: Link coloring with OCG OFF on input line 5726. -Package hyperref Info: PDF/A mode OFF on input line 5731. -LaTeX Info: Redefining \ref on input line 5771. -LaTeX Info: Redefining \pageref on input line 5775. -\Hy@abspage=\count123 - - -Package hyperref Message: Stopped early. - -) - -Package hyperref Message: Driver (autodetected): hpdftex. - -(/usr/local/texlive/2011/texmf-dist/tex/latex/hyperref/hpdftex.def -File: hpdftex.def 2011/04/17 v6.82g Hyperref driver for pdfTeX -\Fld@listcount=\count124 -\c@bookmark@seq@number=\count125 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty -Package: rerunfilecheck 2011/04/15 v1.7 Rerun checks for auxiliary files (HO) -Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2 -82. -)) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaserequires.sty -Package: beamerbaserequires 2010/05/01 (rcs-revision efa082c6111d) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasecompatibility.st -y -Package: beamerbasecompatibility 2010/07/12 (rcs-revision 6648c3177e4e) -) (/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasefont.sty -Package: beamerbasefont 2010/05/10 (rcs-revision cd36e8a33c6b) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsfonts/amssymb.sty -Package: amssymb 2009/06/22 v3.00 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsfonts/amsfonts.sty -Package: amsfonts 2009/06/22 v3.00 Basic AMSFonts support -\@emptytoks=\toks23 -\symAMSa=\mathgroup4 -\symAMSb=\mathgroup5 -LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' -(Font) U/euf/m/n --> U/euf/b/n on input line 96. -))) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasetranslator.sty -Package: beamerbasetranslator 2010/06/11 (rcs-revision 85fd1cc7fc42) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/translator.sty -Package: translator 2010/06/12 ver 1.10 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/translator-lang -uage-mappings.tex))) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasemisc.sty -Package: beamerbasemisc 2010/06/06 (rcs-revision bff0a9294b45) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasetwoscreens.sty -Package: beamerbasetwoscreens 2010/05/01 (rcs-revision efa082c6111d) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseoverlay.sty -Package: beamerbaseoverlay 2010/05/07 (rcs-revision 5584dad462a9) -\beamer@argscount=\count126 -\beamer@lastskipcover=\skip44 -\beamer@trivlistdepth=\count127 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasetitle.sty -Package: beamerbasetitle 2010/06/12 (rcs-revision 717e481ca47a) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasesection.sty -Package: beamerbasesection 2010/06/17 (rcs-revision e0d9401bb743) -\c@lecture=\count128 -\c@part=\count129 -\c@section=\count130 -\c@subsection=\count131 -\c@subsubsection=\count132 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseframe.sty -Package: beamerbaseframe 2010/06/06 (rcs-revision bff0a9294b45) -\beamer@framebox=\box40 -\beamer@frametitlebox=\box41 -\beamer@zoombox=\box42 -\beamer@zoomcount=\count133 -\beamer@zoomframecount=\count134 -\beamer@frametextheight=\dimen164 -\c@subsectionslide=\count135 -\beamer@frametopskip=\skip45 -\beamer@framebottomskip=\skip46 -\beamer@frametopskipautobreak=\skip47 -\beamer@framebottomskipautobreak=\skip48 -\beamer@envbody=\toks24 -\c@framenumber=\count136 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseverbatim.sty -Package: beamerbaseverbatim 2010/05/01 (rcs-revision efa082c6111d) -\beamer@verbatimfileout=\write4 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseframesize.sty -Package: beamerbaseframesize 2010/06/27 (rcs-revision 6baa2d92e6f1) -\beamer@splitbox=\box43 -\beamer@autobreakcount=\count137 -\beamer@autobreaklastheight=\dimen165 -\beamer@frametitletoks=\toks25 -\beamer@framesubtitletoks=\toks26 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseframecomponents. -sty -Package: beamerbaseframecomponents 2010/07/12 (rcs-revision 09e82992d9b1) -\beamer@footins=\box44 -) (/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasecolor.sty -Package: beamerbasecolor 2010/06/06 (rcs-revision d1a9b48be06d) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasenotes.sty -Package: beamerbasenotes 2010/05/01 (rcs-revision efa082c6111d) -\beamer@frameboxcopy=\box45 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasetoc.sty -Package: beamerbasetoc 2010/06/11 (rcs-revision 242ecaa6783b) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasetemplates.sty -Package: beamerbasetemplates 2010/05/01 (rcs-revision efa082c6111d) -\beamer@sbttoks=\toks27 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseauxtemplates.sty -Package: beamerbaseauxtemplates 2010/05/01 (rcs-revision efa082c6111d) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaseboxes.sty -Package: beamerbaseboxes 2010/05/01 (rcs-revision efa082c6111d) -\bmb@box=\box46 -\bmb@colorbox=\box47 -\bmb@boxshadow=\box48 -\bmb@boxshadowball=\box49 -\bmb@boxshadowballlarge=\box50 -\bmb@temp=\dimen166 -\bmb@dima=\dimen167 -\bmb@dimb=\dimen168 -\bmb@prevheight=\dimen169 -) -\beamer@blockheadheight=\dimen170 -)) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbaselocalstructure.s -ty -Package: beamerbaselocalstructure 2010/06/01 (rcs-revision 81f9e33f7cc2) - (/usr/local/texlive/2011/texmf-dist/tex/latex/tools/enumerate.sty -Package: enumerate 1999/03/05 v3.00 enumerate extensions (DPC) -\@enLab=\toks28 -) -\c@figure=\count138 -\c@table=\count139 -\abovecaptionskip=\skip49 -\belowcaptionskip=\skip50 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasenavigation.sty -Package: beamerbasenavigation 2010/05/01 (rcs-revision efa082c6111d) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasetheorems.sty -Package: beamerbasetheorems 2010/06/06 (rcs-revision 7e7cc5e53e9d) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsmath/amsmath.sty -Package: amsmath 2000/07/18 v2.13 AMS math features -\@mathmargin=\skip51 - -For additional information on amsmath, use the `?' option. -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsmath/amstext.sty -Package: amstext 2000/06/29 v2.01 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsmath/amsgen.sty -File: amsgen.sty 1999/11/30 v2.0 -\@emptytoks=\toks29 -\ex@=\dimen171 -)) -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsmath/amsbsy.sty -Package: amsbsy 1999/11/29 v1.2d -\pmbraise@=\dimen172 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsmath/amsopn.sty -Package: amsopn 1999/12/14 v2.01 operator names -) -\inf@bad=\count140 -LaTeX Info: Redefining \frac on input line 211. -\uproot@=\count141 -\leftroot@=\count142 -LaTeX Info: Redefining \overline on input line 307. -\classnum@=\count143 -\DOTSCASE@=\count144 -LaTeX Info: Redefining \ldots on input line 379. -LaTeX Info: Redefining \dots on input line 382. -LaTeX Info: Redefining \cdots on input line 467. -\Mathstrutbox@=\box51 -\strutbox@=\box52 -\big@size=\dimen173 -LaTeX Font Info: Redeclaring font encoding OML on input line 567. -LaTeX Font Info: Redeclaring font encoding OMS on input line 568. -\macc@depth=\count145 -\c@MaxMatrixCols=\count146 -\dotsspace@=\muskip11 -\c@parentequation=\count147 -\dspbrk@lvl=\count148 -\tag@help=\toks30 -\row@=\count149 -\column@=\count150 -\maxfields@=\count151 -\andhelp@=\toks31 -\eqnshift@=\dimen174 -\alignsep@=\dimen175 -\tagshift@=\dimen176 -\tagwidth@=\dimen177 -\totwidth@=\dimen178 -\lineht@=\dimen179 -\@envbody=\toks32 -\multlinegap=\skip52 -\multlinetaggap=\skip53 -\mathdisplay@stack=\toks33 -LaTeX Info: Redefining \[ on input line 2666. -LaTeX Info: Redefining \] on input line 2667. -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/amscls/amsthm.sty -Package: amsthm 2009/07/02 v2.20.1 -\thm@style=\toks34 -\thm@bodyfont=\toks35 -\thm@headfont=\toks36 -\thm@notefont=\toks37 -\thm@headpunct=\toks38 -\thm@preskip=\skip54 -\thm@postskip=\skip55 -\thm@headsep=\skip56 -\dth@everypar=\toks39 -) -\c@theorem=\count152 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/beamerbasethemes.sty -Package: beamerbasethemes 2010/05/01 (rcs-revision efa082c6111d) -)) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/theme/beamerthemede -fault.sty -Package: beamerthemedefault 2010/06/17 (rcs-revision d02a7cf4d8ae) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/font/beamerfontthem -edefault.sty -Package: beamerfontthemedefault 2010/06/17 (rcs-revision d02a7cf4d8ae) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/color/beamercolorth -emedefault.sty -Package: beamercolorthemedefault 2010/06/17 (rcs-revision d02a7cf4d8ae) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/inner/beamerinnerth -emedefault.sty -Package: beamerinnerthemedefault 2010/06/17 (rcs-revision d02a7cf4d8ae) -\beamer@dima=\dimen180 -\beamer@dimb=\dimen181 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/outer/beamerouterth -emedefault.sty -Package: beamerouterthemedefault 2010/06/17 (rcs-revision d02a7cf4d8ae) -))) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/theme/beamerthemeWa -rsaw.sty -Package: beamerthemeWarsaw 2010/06/17 (rcs-revision d02a7cf4d8ae) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/inner/beamerinnerth -emerounded.sty -Package: beamerinnerthemerounded 2010/06/17 (rcs-revision d02a7cf4d8ae) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/outer/beamerouterth -emeshadow.sty -Package: beamerouterthemeshadow 2010/06/17 (rcs-revision d02a7cf4d8ae) - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/outer/beamerouterth -emesplit.sty -Package: beamerouterthemesplit 2010/06/17 (rcs-revision d02a7cf4d8ae) -)) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/color/beamercolorth -emeorchid.sty -Package: beamercolorthemeorchid 2010/06/17 (rcs-revision d02a7cf4d8ae) -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/themes/color/beamercolorth -emewhale.sty -Package: beamercolorthemewhale 2010/06/17 (rcs-revision d02a7cf4d8ae) -)) -(/usr/local/texlive/2011/texmf-dist/tex/latex/listings/listings.sty -\lst@mode=\count153 -\lst@gtempboxa=\box53 -\lst@token=\toks40 -\lst@length=\count154 -\lst@currlwidth=\dimen182 -\lst@column=\count155 -\lst@pos=\count156 -\lst@lostspace=\dimen183 -\lst@width=\dimen184 -\lst@newlines=\count157 -\lst@lineno=\count158 -\lst@maxwidth=\dimen185 - -(/usr/local/texlive/2011/texmf-dist/tex/latex/listings/lstmisc.sty -File: lstmisc.sty 2007/02/22 1.4 (Carsten Heinz) -\c@lstnumber=\count159 -\lst@skipnumbers=\count160 -\lst@framebox=\box54 -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/listings/listings.cfg -File: listings.cfg 2007/02/22 1.4 listings configuration -)) -Package: listings 2007/02/22 1.4 (Carsten Heinz) - -(./presentation-week-05.aux) -\openout1 = `presentation-week-05.aux'. - -LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 15. -LaTeX Font Info: ... okay on input line 15. -LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 15. -LaTeX Font Info: ... okay on input line 15. -LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 15. -LaTeX Font Info: ... okay on input line 15. -LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 15. -LaTeX Font Info: ... okay on input line 15. -LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 15. -LaTeX Font Info: ... okay on input line 15. -LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 15. -LaTeX Font Info: ... okay on input line 15. -LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 15. -LaTeX Font Info: ... okay on input line 15. - -*geometry* driver: auto-detecting -*geometry* detected driver: pdftex -*geometry* verbose mode - [ preamble ] result: -* driver: pdftex -* paper: custom -* layout: -* layoutoffset:(h,v)=(0.0pt,0.0pt) -* modes: includehead includefoot -* h-part:(L,W,R)=(28.45274pt, 307.28987pt, 28.45274pt) -* v-part:(T,H,B)=(0.0pt, 273.14662pt, 0.0pt) -* \paperwidth=364.19536pt -* \paperheight=273.14662pt -* \textwidth=307.28987pt -* \textheight=244.6939pt -* \oddsidemargin=-43.81725pt -* \evensidemargin=-43.81725pt -* \topmargin=-72.26999pt -* \headheight=14.22636pt -* \headsep=0.0pt -* \topskip=11.0pt -* \footskip=14.22636pt -* \marginparwidth=4.0pt -* \marginparsep=10.0pt -* \columnsep=10.0pt -* \skip\footins=10.0pt plus 4.0pt minus 2.0pt -* \hoffset=0.0pt -* \voffset=0.0pt -* \mag=1000 -* \@twocolumnfalse -* \@twosidefalse -* \@mparswitchfalse -* \@reversemarginfalse -* (1in=72.27pt=25.4mm, 1cm=28.453pt) - -(/usr/local/texlive/2011/texmf-dist/tex/context/base/supp-pdf.mkii -[Loading MPS to PDF converter (version 2006.09.02).] -\scratchcounter=\count161 -\scratchdimen=\dimen186 -\scratchbox=\box55 -\nofMPsegments=\count162 -\nofMParguments=\count163 -\everyMPshowfont=\toks41 -\MPscratchCnt=\count164 -\MPscratchDim=\dimen187 -\MPnumerator=\count165 -\makeMPintoPDFobject=\count166 -\everyMPtoPDFconversion=\toks42 -) (/usr/local/texlive/2011/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty -Package: epstopdf-base 2010/02/09 v2.5 Base part for package epstopdf - -(/usr/local/texlive/2011/texmf-dist/tex/latex/oberdiek/grfext.sty -Package: grfext 2010/08/19 v1.1 Managing graphics extensions (HO) -) -Package grfext Info: Graphics extension search list: -(grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE -G,.JBIG2,.JB2,.eps] -(grfext) \AppendGraphicsExtensions on input line 452. - -(/usr/local/texlive/2011/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg -File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv -e -)) -ABD: EveryShipout initializing macros -\AtBeginShipoutBox=\box56 -Package hyperref Info: Link coloring OFF on input line 15. - -(/usr/local/texlive/2011/texmf-dist/tex/latex/hyperref/nameref.sty -Package: nameref 2010/04/30 v2.40 Cross-referencing by name of section - -(/usr/local/texlive/2011/texmf-dist/tex/generic/oberdiek/gettitlestring.sty -Package: gettitlestring 2010/12/03 v1.4 Cleanup title references (HO) -) -\c@section@level=\count167 -) -LaTeX Info: Redefining \ref on input line 15. -LaTeX Info: Redefining \pageref on input line 15. -LaTeX Info: Redefining \nameref on input line 15. - -(./presentation-week-05.out) (./presentation-week-05.out) -\@outlinefile=\write5 -\openout5 = `presentation-week-05.out'. - -LaTeX Font Info: Overwriting symbol font `operators' in version `normal' -(Font) OT1/cmr/m/n --> OT1/cmss/m/n on input line 15. -LaTeX Font Info: Overwriting symbol font `operators' in version `bold' -(Font) OT1/cmr/bx/n --> OT1/cmss/bx/n on input line 15. -\symnumbers=\mathgroup6 -\sympureletters=\mathgroup7 -LaTeX Font Info: Overwriting math alphabet `\mathrm' in version `normal' -(Font) OT1/cmss/m/n --> OT1/cmr/m/n on input line 15. -LaTeX Font Info: Redeclaring math alphabet \mathbf on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `normal' -(Font) OT1/cmr/bx/n --> OT1/cmss/bx/n on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `bold' -(Font) OT1/cmr/bx/n --> OT1/cmss/bx/n on input line 15. -LaTeX Font Info: Redeclaring math alphabet \mathsf on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `normal' -(Font) OT1/cmss/m/n --> OT1/cmss/m/n on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' -(Font) OT1/cmss/bx/n --> OT1/cmss/m/n on input line 15. -LaTeX Font Info: Redeclaring math alphabet \mathit on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathit' in version `normal' -(Font) OT1/cmr/m/it --> OT1/cmss/m/it on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' -(Font) OT1/cmr/bx/it --> OT1/cmss/m/it on input line 15. -LaTeX Font Info: Redeclaring math alphabet \mathtt on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `normal' -(Font) OT1/cmtt/m/n --> OT1/cmtt/m/n on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' -(Font) OT1/cmtt/m/n --> OT1/cmtt/m/n on input line 15. -LaTeX Font Info: Overwriting symbol font `numbers' in version `bold' -(Font) OT1/cmss/m/n --> OT1/cmss/bx/n on input line 15. -LaTeX Font Info: Overwriting symbol font `pureletters' in version `bold' -(Font) OT1/cmss/m/it --> OT1/cmss/bx/it on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathrm' in version `bold' -(Font) OT1/cmss/bx/n --> OT1/cmr/bx/n on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `bold' -(Font) OT1/cmss/bx/n --> OT1/cmss/bx/n on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' -(Font) OT1/cmss/m/n --> OT1/cmss/bx/n on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' -(Font) OT1/cmss/m/it --> OT1/cmss/bx/it on input line 15. -LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' -(Font) OT1/cmtt/m/n --> OT1/cmtt/bx/n on input line 15. - -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/dicts/translato -r-basic-dictionary/translator-basic-dictionary-English.dict -Dictionary: translator-basic-dictionary, Language: English -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/dicts/translato -r-bibliography-dictionary/translator-bibliography-dictionary-English.dict -Dictionary: translator-bibliography-dictionary, Language: English -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/dicts/translato -r-environment-dictionary/translator-environment-dictionary-English.dict -Dictionary: translator-environment-dictionary, Language: English -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/dicts/translato -r-months-dictionary/translator-months-dictionary-English.dict -Dictionary: translator-months-dictionary, Language: English -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/dicts/translato -r-numbers-dictionary/translator-numbers-dictionary-English.dict -Dictionary: translator-numbers-dictionary, Language: English -) -(/usr/local/texlive/2011/texmf-dist/tex/latex/beamer/translator/dicts/translato -r-theorem-dictionary/translator-theorem-dictionary-English.dict -Dictionary: translator-theorem-dictionary, Language: English -) -\c@lstlisting=\count168 - -(./presentation-week-05.nav) - -LaTeX Font Warning: Font shape `OT1/cmss/m/n' in size <4> not available -(Font) size <5> substituted on input line 20. - -[1{/usr/local/texlive/2011/texmf-var/fonts/map/pdftex/updmap/pdftex.map} - -] -(./presentation-week-05.toc) [2 - -] [3 - -] [4 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [5 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb -LaTeX Font Info: Try loading font information for U+msa on input line 12. - -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsfonts/umsa.fd -File: umsa.fd 2009/06/22 v3.00 AMS symbols A -) -LaTeX Font Info: Try loading font information for U+msb on input line 12. - -(/usr/local/texlive/2011/texmf-dist/tex/latex/amsfonts/umsb.fd -File: umsb.fd 2009/06/22 v3.00 AMS symbols B -)) [6 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [7 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [8 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [9 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [10 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [11 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [12 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [13 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [14 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [15 - -] [16 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) -Overfull \vbox (3.35751pt too high) detected at line 330 - [] - -[17 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [18 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [19 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) -Overfull \vbox (3.35751pt too high) detected at line 389 - [] - -[20 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb -Overfull \hbox (26.13402pt too wide) in paragraph at lines 14--14 -[] \OT1/cmtt/m/n/10.95 print "position: %s, %s -- shape: %s, %s"%(x, y, w, h -)[] - [] - -) [21 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [22 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [23 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [24 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [25 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb -Overfull \hbox (14.63664pt too wide) in paragraph at lines 6--6 -[]\OT1/cmtt/m/n/10.95 [expression for variable in a_list if something_is_true][ -] - [] - -) [26 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [27 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb -Overfull \hbox (3.13927pt too wide) in paragraph at lines 12--12 -[]\OT1/cmtt/m/n/10.95 [name for name in dir(__builtin__) if "Error" in name][] - - [] - -) [28 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [29 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [30 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [31 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [32 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [33 - -] [34 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [35 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [36 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [37 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb -Overfull \hbox (49.70702pt too wide) in paragraph at lines 19--19 -[] \OT1/cmtt/m/n/10 # make sure the shuffled sequence does not lose any -elements[] - [] - - -Overfull \hbox (12.95734pt too wide) in paragraph at lines 19--19 -[] \OT1/cmtt/m/n/10 # should raise an exception for an immutable sequenc -e[] - [] - - -Overfull \hbox (12.95734pt too wide) in paragraph at lines 19--19 -[] \OT1/cmtt/m/n/10 self.assertRaises(TypeError, random.shuffle, (1,2,3) -)[] - [] - -) -Overfull \vbox (7.17966pt too high) detected at line 742 - [] - -[38 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [39 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [40 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [41 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [42 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb -Overfull \hbox (28.7072pt too wide) in paragraph at lines 20--20 -[] \OT1/cmtt/m/n/10 # make sure the shuffled sequence does not lose any elem -ents[] - [] - -) -Overfull \vbox (7.9463pt too high) detected at line 846 - [] - -[43 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [44 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [45 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb -Overfull \hbox (28.7072pt too wide) in paragraph at lines 18--18 -[] \OT1/cmtt/m/n/10 # make sure the shuffled sequence does not lose any elem -ents[] - [] - -) [46 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [47 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [48 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! -Missing character: There is no in font cmtt12! - -Overfull \hbox (11.33963pt too wide) in paragraph at lines 11--12 -[][]\OT1/cmtt/m/n/14.4 nosetests --with-coverage test_codingbat.py - [] - -) [49 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [50 - -] -\openout4 = `presentation-week-05.vrb'. - - (./presentation-week-05.vrb) [51 - -] -\openout4 = `presentation-week-05.vrb'. - - -(./presentation-week-05.vrb) [52 - -] -\tf@nav=\write6 -\openout6 = `presentation-week-05.nav'. - -\tf@toc=\write7 -\openout7 = `presentation-week-05.toc'. - -\tf@snm=\write8 -\openout8 = `presentation-week-05.snm'. - -Package atveryend Info: Empty hook `BeforeClearDocument' on input line 1068. -Package atveryend Info: Empty hook `AfterLastShipout' on input line 1068. - (./presentation-week-05.aux) -Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 1068. -Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 1068. - -Package rerunfilecheck Info: File `presentation-week-05.out' has not changed. -(rerunfilecheck) Checksum: 57794C8D06794128DF86960A8EE2428E;263. - - -LaTeX Font Warning: Size substitutions with differences -(Font) up to 1.0pt have occurred. - -Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 1068. - ) -Here is how much of TeX's memory you used: - 17056 strings out of 493633 - 316943 string characters out of 3143378 - 389869 words of memory out of 3000000 - 19761 multiletter control sequences out of 15000+200000 - 15076 words of font info for 58 fonts, out of 3000000 for 9000 - 831 hyphenation exceptions out of 8191 - 49i,19n,60p,422b,592s stack positions out of 5000i,500n,10000p,200000b,50000s - -< -/usr/local/texlive/2011/texmf-dist/fonts/type1/public/amsfonts/cm/cmss8.pfb> -Output written on presentation-week-05.pdf (52 pages, 189923 bytes). -PDF statistics: - 1766 PDF objects out of 2073 (max. 8388607) - 1671 compressed objects within 17 object streams - 110 named destinations out of 1000 (max. 500000) - 121 words of extra memory for PDF output out of 10000 (max. 10000000) - diff --git a/slides_sources/old_versions/week-05/presentation-week-05.nav b/slides_sources/old_versions/week-05/presentation-week-05.nav deleted file mode 100644 index 93028d26..00000000 --- a/slides_sources/old_versions/week-05/presentation-week-05.nav +++ /dev/null @@ -1,125 +0,0 @@ -\beamer@endinputifotherversion {3.10pt} -\headcommand {\slideentry {0}{0}{1}{1/1}{}{0}} -\headcommand {\beamer@framepages {1}{1}} -\headcommand {\slideentry {0}{0}{2}{2/2}{}{0}} -\headcommand {\beamer@framepages {2}{2}} -\headcommand {\sectionentry {1}{Review/Questions}{3}{Review/Questions}{0}} -\headcommand {\beamer@sectionpages {1}{2}} -\headcommand {\beamer@subsectionpages {1}{2}} -\headcommand {\slideentry {1}{0}{3}{3/3}{}{0}} -\headcommand {\beamer@framepages {3}{3}} -\headcommand {\slideentry {1}{0}{4}{4/4}{}{0}} -\headcommand {\beamer@framepages {4}{4}} -\headcommand {\slideentry {1}{0}{5}{5/5}{}{0}} -\headcommand {\beamer@framepages {5}{5}} -\headcommand {\sectionentry {2}{Unicode}{6}{Unicode}{0}} -\headcommand {\beamer@sectionpages {3}{5}} -\headcommand {\beamer@subsectionpages {3}{5}} -\headcommand {\slideentry {2}{0}{6}{6/6}{}{0}} -\headcommand {\beamer@framepages {6}{6}} -\headcommand {\slideentry {2}{0}{7}{7/7}{}{0}} -\headcommand {\beamer@framepages {7}{7}} -\headcommand {\slideentry {2}{0}{8}{8/8}{}{0}} -\headcommand {\beamer@framepages {8}{8}} -\headcommand {\slideentry {2}{0}{9}{9/9}{}{0}} -\headcommand {\beamer@framepages {9}{9}} -\headcommand {\slideentry {2}{0}{10}{10/10}{}{0}} -\headcommand {\beamer@framepages {10}{10}} -\headcommand {\slideentry {2}{0}{11}{11/11}{}{0}} -\headcommand {\beamer@framepages {11}{11}} -\headcommand {\slideentry {2}{0}{12}{12/12}{}{0}} -\headcommand {\beamer@framepages {12}{12}} -\headcommand {\slideentry {2}{0}{13}{13/13}{}{0}} -\headcommand {\beamer@framepages {13}{13}} -\headcommand {\slideentry {2}{0}{14}{14/14}{}{0}} -\headcommand {\beamer@framepages {14}{14}} -\headcommand {\slideentry {2}{0}{15}{15/15}{}{0}} -\headcommand {\beamer@framepages {15}{15}} -\headcommand {\slideentry {2}{0}{16}{16/16}{}{0}} -\headcommand {\beamer@framepages {16}{16}} -\headcommand {\sectionentry {3}{Advanced Argument Passing}{17}{Advanced Argument Passing}{0}} -\headcommand {\beamer@sectionpages {6}{16}} -\headcommand {\beamer@subsectionpages {6}{16}} -\headcommand {\slideentry {3}{0}{17}{17/17}{}{0}} -\headcommand {\beamer@framepages {17}{17}} -\headcommand {\slideentry {3}{0}{18}{18/18}{}{0}} -\headcommand {\beamer@framepages {18}{18}} -\headcommand {\slideentry {3}{0}{19}{19/19}{}{0}} -\headcommand {\beamer@framepages {19}{19}} -\headcommand {\slideentry {3}{0}{20}{20/20}{}{0}} -\headcommand {\beamer@framepages {20}{20}} -\headcommand {\slideentry {3}{0}{21}{21/21}{}{0}} -\headcommand {\beamer@framepages {21}{21}} -\headcommand {\slideentry {3}{0}{22}{22/22}{}{0}} -\headcommand {\beamer@framepages {22}{22}} -\headcommand {\slideentry {3}{0}{23}{23/23}{}{0}} -\headcommand {\beamer@framepages {23}{23}} -\headcommand {\sectionentry {4}{List and Dict Comprehensions}{24}{List and Dict Comprehensions}{0}} -\headcommand {\beamer@sectionpages {17}{23}} -\headcommand {\beamer@subsectionpages {17}{23}} -\headcommand {\slideentry {4}{0}{24}{24/24}{}{0}} -\headcommand {\beamer@framepages {24}{24}} -\headcommand {\slideentry {4}{0}{25}{25/25}{}{0}} -\headcommand {\beamer@framepages {25}{25}} -\headcommand {\slideentry {4}{0}{26}{26/26}{}{0}} -\headcommand {\beamer@framepages {26}{26}} -\headcommand {\slideentry {4}{0}{27}{27/27}{}{0}} -\headcommand {\beamer@framepages {27}{27}} -\headcommand {\slideentry {4}{0}{28}{28/28}{}{0}} -\headcommand {\beamer@framepages {28}{28}} -\headcommand {\slideentry {4}{0}{29}{29/29}{}{0}} -\headcommand {\beamer@framepages {29}{29}} -\headcommand {\slideentry {4}{0}{30}{30/30}{}{0}} -\headcommand {\beamer@framepages {30}{30}} -\headcommand {\slideentry {4}{0}{31}{31/31}{}{0}} -\headcommand {\beamer@framepages {31}{31}} -\headcommand {\slideentry {4}{0}{32}{32/32}{}{0}} -\headcommand {\beamer@framepages {32}{32}} -\headcommand {\slideentry {4}{0}{33}{33/33}{}{0}} -\headcommand {\beamer@framepages {33}{33}} -\headcommand {\slideentry {4}{0}{34}{34/34}{}{0}} -\headcommand {\beamer@framepages {34}{34}} -\headcommand {\sectionentry {5}{Unit Testing}{35}{Unit Testing}{0}} -\headcommand {\beamer@sectionpages {24}{34}} -\headcommand {\beamer@subsectionpages {24}{34}} -\headcommand {\slideentry {5}{0}{35}{35/35}{}{0}} -\headcommand {\beamer@framepages {35}{35}} -\headcommand {\slideentry {5}{0}{36}{36/36}{}{0}} -\headcommand {\beamer@framepages {36}{36}} -\headcommand {\slideentry {5}{0}{37}{37/37}{}{0}} -\headcommand {\beamer@framepages {37}{37}} -\headcommand {\slideentry {5}{0}{38}{38/38}{}{0}} -\headcommand {\beamer@framepages {38}{38}} -\headcommand {\slideentry {5}{0}{39}{39/39}{}{0}} -\headcommand {\beamer@framepages {39}{39}} -\headcommand {\slideentry {5}{0}{40}{40/40}{}{0}} -\headcommand {\beamer@framepages {40}{40}} -\headcommand {\slideentry {5}{0}{41}{41/41}{}{0}} -\headcommand {\beamer@framepages {41}{41}} -\headcommand {\slideentry {5}{0}{42}{42/42}{}{0}} -\headcommand {\beamer@framepages {42}{42}} -\headcommand {\slideentry {5}{0}{43}{43/43}{}{0}} -\headcommand {\beamer@framepages {43}{43}} -\headcommand {\slideentry {5}{0}{44}{44/44}{}{0}} -\headcommand {\beamer@framepages {44}{44}} -\headcommand {\slideentry {5}{0}{45}{45/45}{}{0}} -\headcommand {\beamer@framepages {45}{45}} -\headcommand {\slideentry {5}{0}{46}{46/46}{}{0}} -\headcommand {\beamer@framepages {46}{46}} -\headcommand {\slideentry {5}{0}{47}{47/47}{}{0}} -\headcommand {\beamer@framepages {47}{47}} -\headcommand {\slideentry {5}{0}{48}{48/48}{}{0}} -\headcommand {\beamer@framepages {48}{48}} -\headcommand {\slideentry {5}{0}{49}{49/49}{}{0}} -\headcommand {\beamer@framepages {49}{49}} -\headcommand {\slideentry {5}{0}{50}{50/50}{}{0}} -\headcommand {\beamer@framepages {50}{50}} -\headcommand {\slideentry {5}{0}{51}{51/51}{}{0}} -\headcommand {\beamer@framepages {51}{51}} -\headcommand {\slideentry {5}{0}{52}{52/52}{}{0}} -\headcommand {\beamer@framepages {52}{52}} -\headcommand {\beamer@partpages {1}{52}} -\headcommand {\beamer@subsectionpages {35}{52}} -\headcommand {\beamer@sectionpages {35}{52}} -\headcommand {\beamer@documentpages {52}} -\headcommand {\def \inserttotalframenumber {52}} diff --git a/slides_sources/old_versions/week-05/presentation-week-05.out b/slides_sources/old_versions/week-05/presentation-week-05.out deleted file mode 100644 index 73ecc990..00000000 --- a/slides_sources/old_versions/week-05/presentation-week-05.out +++ /dev/null @@ -1,5 +0,0 @@ -\BOOKMARK [2][]{Outline0.1}{Review/Questions}{}% 1 -\BOOKMARK [2][]{Outline0.2}{Unicode}{}% 2 -\BOOKMARK [2][]{Outline0.3}{Advanced Argument Passing}{}% 3 -\BOOKMARK [2][]{Outline0.4}{List and Dict Comprehensions}{}% 4 -\BOOKMARK [2][]{Outline0.5}{Unit Testing}{}% 5 diff --git a/slides_sources/old_versions/week-05/presentation-week-05.pdf b/slides_sources/old_versions/week-05/presentation-week-05.pdf deleted file mode 100644 index 0ecf9034..00000000 Binary files a/slides_sources/old_versions/week-05/presentation-week-05.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-05/presentation-week-05.tex b/slides_sources/old_versions/week-05/presentation-week-05.tex deleted file mode 100644 index 00611026..00000000 --- a/slides_sources/old_versions/week-05/presentation-week-05.tex +++ /dev/null @@ -1,1070 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Intro to Python: Week 1]{Introduction to Python\\ -Unicode, Advanced Argument passing\\ -List and Dict Comprehensions, Testing -} -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{October 29, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - - -\section{Review/Questions} - -% --------------------------------------------- -\begin{frame}{Review of Previous Class} - -\begin{itemize} - \item Dictionaries - \item Exceptions - \item Files, etc. -\end{itemize} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning talks today:} - -\vfill -{\Large -Rithy Chhen - -\vfill -Howard Edson - -\vfill -Dong Kang - -\vfill -Steven Werner - -} -\vfill - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Homework review} - - \vfill - {\Large Homework Questions? } - - \vfill - {\Large My Solution} - - (\verb|dict.setdefault()| trick...) - - \vfill -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Unicode} - -%--------------------------------- -\begin{frame}[fragile]{Unicode} - -{\Large I hope you all read this:} - -\vfill -{\Large -\centering -The Absolute Minimum Every Software Developer Absolutely, -Positively Must Know About Unicode and Character Sets (No Excuses!) - -} - -\vfill -\url{http://www.joelonsoftware.com/articles/Unicode.html} - -\vfill -{\Large If not -- go read it!} - -\end{frame} - -\begin{frame}[fragile]{Unicode} - -{\Large -\vfill - -Everything is bytes - -\vfill -If it's on disk or transmitted over a network, it's bytes - -\vfill -Python provides some abstractions to make it easier to deal with bytes - -\vfill -} - -\end{frame} - -\begin{frame}[fragile]{Unicode} - -{\Large -\vfill - -Unicode is a biggie - -\vfill -Strings vs Unicode -} - -{\large (\verb|str()| vs. \verb|bytes()| vs. \verb|unicode()| ) } - -\vfill -{\Large Python 2.x vs 3.x} - - -\vfill -(actually, dealing with numbers rather than bytes is big -- but we take that for granted) - -\end{frame} - -\begin{frame}[fragile]{Unicode} - -{\Large -\vfill -Strings are sequences of bytes - -\vfill -Unicode strings are sequences of platonic characters - -\vfill -Platonic characters cannot be written to disk or network! -} -\vfill -(ANSI -- one character == one byte -- so easy!) -\end{frame} - -\begin{frame}[fragile]{Unicode} - -{\Large -\vfill -The \verb|unicode| object lets you work with characters - -\vfill -``Encoding'' is converting from a unicode object to bytes - -\vfill -``Decoding'' is converting from bytes to a unicode object -} - -\vfill -\end{frame} - -\begin{frame}[fragile]{Unicode} - -{\large -\begin{verbatim} -import codecs -ord() -chr() -unichr() -str() -unicode() -encode() -decode() -\end{verbatim} -} -\end{frame} - -\begin{frame}[fragile]{Unicode Literals} - - -{\Large 1) Use unicode in your source files:} - -\begin{verbatim} -# -*- coding: utf-8 -*- -\end{verbatim} - -\vfill -{\Large 2) escape the unicode characters} - -\begin{verbatim} -print u"The integral sign: \u222B" -print u"The integral sign: \N{integral}" -\end{verbatim} - -{\large lots of tables of code points online:} - -\url{http://inamidst.com/stuff/unidata/} - -\vfill -(demo: \verb|code\hello_unicode.py|) -\end{frame} - - -%--------------------------------- -\begin{frame}[fragile]{Unicode} - -{\Large -Use unicode objects in all your code - -\vfill -decode on input - -\vfill -encode on output - -\vfill -Many packages do this for you\\ -\hspace{0.25in} (XML processing, databases, ...) - -\vfill -Gotcha:\\ -\hspace{0.25in} Python has a default encoding (usually ascii) -} -\end{frame} - -\begin{frame}[fragile]{Unicode} - -{\Large Python Docs Unicode HowTo:} - -\url{http://docs.python.org/howto/unicode.html} - -\vfill -{\Large ``Reading Unicode from a file is therefore simple:''} - -\begin{verbatim} -import codecs -f = codecs.open('unicode.rst', encoding='utf-8') -for line in f: - print repr(line) -\end{verbatim} - -\vfill -{\Large Encodings Built-in to Python:} - -\url{http://docs.python.org/2/library/codecs.html#standard-encodings} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Unicode LAB} - -\begin{itemize} - \item Find some nifty non-ascii characters you might use.\\ - Create a unicode object with them in two different ways. - \item In the "code" dir for this week, there are two files:\\ - \verb|text.utf16| \\ - \verb|text.utf32| \\ - read the contents into unicode objects - \item write some of the text from the first exercise to file. - \item read that file back in. -\end{itemize} - -\vfill -(reference: \url{http://inamidst.com/stuff/unidata/}) - -\vfill -NOTE: if your terminal does not support unicode -- you'll get an error trying -to print. Try a different terminal or IDE, or google for a solution -\end{frame} - - - -%------------------------------- -\begin{frame}{Lightning Talk} - -{\LARGE Lightning Talks:} - -{\large -\vfill -Rithy Chhen - -\vfill -Howard Edson -} - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Advanced Argument Passing} - - -% --------------------------------------------- -\begin{frame}[fragile]{Keyword arguments} - - {\Large When defining a function, you can specify only - what you need -- any order} - -\begin{verbatim} -In [151]: def fun(x,y=0,z=0): - print x,y,z - .....: - -In [152]: fun(1,2,3) -1 2 3 - -In [153]: fun(1, z=3) -1 0 3 - -In [154]: fun(1, z=3, y=2) -1 2 3 -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Keyword arguments} - - {\Large A Common Idiom:} - -\vfill -\begin{verbatim} -def fun(x, y=None): - if y is None: - do_something_different - - go_on_here -\end{verbatim} -\vfill - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Keyword arguments} - - {\Large Can set defaults to variables} - -\begin{verbatim} -In [156]: y = 4 - -In [157]: def fun(x=y): - print "x is:", x - .....: - -In [158]: fun() -x is: 4 - -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Keyword arguments} - -{\Large Defaults are evaluated when the function is defined} - -\begin{verbatim} -In [156]: y = 4 - -In [157]: def fun(x=y): - print "x is:", x - .....: - -In [158]: fun() -x is: 4 - -In [159]: y = 6 - -In [160]: fun() -x is: 4 -\end{verbatim} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Function arguments in variables} - -{\Large function arguments are really just\\ - -- a tuple (positional arguments) \\ - -- a dict (keyword arguments) \\ -} -\begin{verbatim} -def f(x, y, w=0, h=0): - print "position: %s, %s -- shape: %s, %s"%(x, y, w, h) - -position = (3,4) -size = {'h': 10, 'w': 20} - ->>> f( *position, **size) -position: 3, 4 -- shape: 20, 10 -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Function parameters in variables} - -{\Large You can also pull in the parameters out in the function as a tuple and a dict -} -\begin{verbatim} -def f(*args, **kwargs): - print "the positional arguments are:", args - print "the keyword arguments are:", kwargs - -In [389]: f(2, 3, this=5, that=7) -the positional arguments are: (2, 3) -the keyword arguments are: {'this': 5, 'that': 7} -\end{verbatim} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large keyword arguments} -\begin{itemize} - \item Write a function that has four optional parameters\\ - (with defaults): - \begin{itemize} - \item foreground\_color - \item background\_color - \item link\_color - \item visited\_link\_color - \end{itemize} - \item Have it print the colors. - \item Call it with a couple different parameters set - \item Have it pull the parameters out with \verb|*args, **kwargs| -\end{itemize} - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{List and Dict Comprehensions} - -% ---------------------------------------------- -\begin{frame}[fragile]{List comprehensions} - -{\Large A bit of functional programming:} - -\begin{verbatim} -new_list = [expression for variable in a_list] -\end{verbatim} - -{\Large same as for loop:} - -\begin{verbatim} -new_list = [] -for variable in a_list: - new_list.append(expression) -\end{verbatim} - -\end{frame} - -% ---------------------------------------------- -\begin{frame}[fragile]{List comprehensions} - -{\Large More than one ``for'':} - -\begin{verbatim} -new_list = \ -[exp for var in a_list for var2 in a_list2] -\end{verbatim} - -{\Large same as nested for loop:} - -\begin{verbatim} -new_list = [] -for var in a_list: - for var2 in a_list2: - new_list.append(expression) -\end{verbatim} - -{\large You get the ``outer product'', i.e. all combinations.} - -\vfill -(demo) -\end{frame} - -% ---------------------------------------------- -\begin{frame}[fragile]{List comprehensions} - -{\Large Add a conditional:} - -\begin{verbatim} -new_list = \ -[expression for variable in a_list if something_is_true] -\end{verbatim} - -{\Large same as for loop:} - -\begin{verbatim} -new_list = [] -for variable in a_list: - if something_is_true: - new_list.append(expression) -\end{verbatim} - -\vfill -(demo) -\end{frame} - - - -% ---------------------------------------------- -\begin{frame}[fragile]{List comprehensions} - -{\Large Examples:} - -\begin{verbatim} -In [341]: [x**2 for x in range(3)] -Out[341]: [0, 1, 4] - -In [342]: [x+y for x in range(3) for y in range(5,7)] -Out[342]: [5, 6, 6, 7, 7, 8] - -In [343]: [x*2 for x in range(6) if not x%2] -Out[343]: [0, 4, 8] -\end{verbatim} - -\end{frame} - - -% ---------------------------------------------- -\begin{frame}[fragile]{List comprehensions} - -{\Large Remember this from last week?} - -\begin{verbatim} -[name for name in dir(__builtin__) if "Error" in name] - -['ArithmeticError', - 'AssertionError', - 'AttributeError', - 'BufferError', - 'EOFError', - .... -\end{verbatim} - -\end{frame} - -% ---------------------------------------------- -\begin{frame}[fragile]{Set Comprehensions} - -{\Large You can do it with sets, too:} - -\begin{verbatim} -new_set = { value for variable in a_sequence} -\end{verbatim} - -{\Large same as for loop:} - -\begin{verbatim} -new_set = set() -for key in a_list: - new_set.add(value) -\end{verbatim} - -\end{frame} - -% ---------------------------------------------- -\begin{frame}[fragile]{Set Comprehensions} - - -\begin{verbatim} -In [33]: s = "a fairly long string" - -In [34]: vowels = 'aeiou' - -In [35]: { l for l in s if l in vowels} -Out[35]: set(['a', 'i', 'o']) -\end{verbatim} - -\end{frame} - - - -% ---------------------------------------------- -\begin{frame}[fragile]{Dict Comprehensions} - -{\Large and with dicts:} - -\begin{verbatim} -new_dict = { key:value for variable in a_sequence} -\end{verbatim} - -{\Large same as for loop:} - -\begin{verbatim} -new_dict = {} -for key in a_list: - new_dict[key] = value -\end{verbatim} - -\end{frame} - -% ---------------------------------------------- -\begin{frame}[fragile]{Dict Comprehensions} - -{\Large Example} - -\begin{verbatim} -In [340]: { i: "this_%i"%i for i in range(5) } -Out[340]: {0: 'this_0', 1: 'this_1', 2: 'this_2', - 3: 'this_3', 4: 'this_4'} -\end{verbatim} - -\vfill -(not as useful with the \verb|dict()| constructor...) -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\Large List and Dict comprehension lab:} - -\vfill -{\large \verb|code/comprehensions.rst[html]| } - -\vfill - -\end{frame} - - -%------------------------------- -\begin{frame}{Lightning Talk} - -{\LARGE Lightning Talks:} - -{\large -\vfill -Dong Kang - -\vfill -Steven Werner -} -\vfill -\end{frame} - - -\section{Unit Testing} - -% --------------------------------------------- -\begin{frame}[fragile]{Unit Testing} - -{\LARGE Gaining Traction} - -\vfill -{\Large You need to test your code somehow when you write it -- - why not preserve those tests?} - -\vfill -{\Large And allow you to auto-run them later?} - -\vfill -{\LARGE Test-Driven development:}\\[0.1in] -{\Large \hspace{0.3in} Write the tests before the code} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Unit Testing} - -{\LARGE My thoughts:} - -\vfill -{\Large Unit testing encourages clean, decoupled design} - -\vfill -{\Large If it's hard to write unit tests for -- it's not well designed} - -\vfill -{\Large but...} - -\vfill -{\Large ``complete'' test coverage is a fantasy} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{PyUnit} - -{\LARGE PyUnit: the stdlib unit testing framework} - -\vfill -{\Large \verb|import unittest|} - -\vfill -{\Large More or less a port of Junit from Java} - -\vfill -{\Large A bit verbose: you have to write classes \& methods} - -\vfill -{\large (And we haven't covered that yet!)} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{unittest example} - -{\small -\begin{verbatim} -import random -import unittest - -class TestSequenceFunctions(unittest.TestCase): - - def setUp(self): - self.seq = range(10) - - def test_shuffle(self): - # make sure the shuffled sequence does not lose any elements - random.shuffle(self.seq) - self.seq.sort() - self.assertEqual(self.seq, range(10)) - - # should raise an exception for an immutable sequence - self.assertRaises(TypeError, random.shuffle, (1,2,3)) -\end{verbatim} -} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{unittest example (cont)} - -{\small -\begin{verbatim} - def test_choice(self): - element = random.choice(self.seq) - self.assertTrue(element in self.seq) - - def test_sample(self): - with self.assertRaises(ValueError): - random.sample(self.seq, 20) - for element in random.sample(self.seq, 5): - self.assertTrue(element in self.seq) - -if __name__ == '__main__': - unittest.main() -\end{verbatim} -} - -\vfill -(\verb|code/unitest_example.py|) - -\vfill -\url{http://docs.python.org/library/unittest.html} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{unittest} - -{\Large Lots of good tutorials out there:} - -\vfill -{\Large Google: ``python unittest tutorial''} - -\vfill -{\Large I first learned from this one:}\\[0.1in] -\url{http://www.diveintopython.net/unit_testing/index.html} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{nose and pytest} - -{\Large Due to its Java heritage, unittest is kind of verbose} - -\vfill -{\Large Also no test discovery}\\ -{\large \hspace{0.2in}(though unittest2 does add that...) } - -\vfill -{\Large So folks invented nose and pytest} - -\end{frame} - -\begin{frame}[fragile]{nose} - -{\LARGE \verb|nose|} - -\vfill -{\Large \hspace{0.2in} Is nicer testing for python} - -\vfill -{\Large \hspace{0.2in} nose extends unittest to make testing easier.} - -\vfill -\begin{verbatim} - $ pip install nose - - $ nosetests unittest_example.py -\end{verbatim} - -\vfill -\url{http://nose.readthedocs.org/en/latest/} -\end{frame} - -\begin{frame}[fragile]{nose example} - -{\Large The same example -- with nose} - -{\small -\begin{verbatim} -import random -import nose.tools - -seq = range(10) - -def test_shuffle(): - # make sure the shuffled sequence does not lose any elements - random.shuffle(seq) - seq.sort() - assert seq == range(10) - -@nose.tools.raises(TypeError) -def test_shuffle_immutable(): - # should raise an exception for an immutable sequence - random.shuffle( (1,2,3) ) -\end{verbatim} -} - -\end{frame} - -\begin{frame}[fragile]{nose example (cont) } - -{\small -\begin{verbatim} -def test_choice(): - element = random.choice(seq) - assert (element in seq) - -def test_sample(): - for element in random.sample(seq, 5): - assert element in seq - -@nose.tools.raises(ValueError) -def test_sample_too_large(): - random.sample(seq, 20) -\end{verbatim} -} - -\vfill -(\verb|code/test_random_nose.py|) - -\end{frame} - - -\begin{frame}[fragile]{pytest} - -{\LARGE \verb|pytest|} - -\vfill -{\Large \hspace{0.2in} A mature full-featured testing tool} - -\vfill -{\Large \hspace{0.2in} Provides no-boilerplate testing} - -\vfill -{\Large \hspace{0.2in} Integrates many common testing methods} - -\vfill -\begin{verbatim} - $ pip install pytest - - $ py.test unittest_example.py -\end{verbatim} - -\vfill -\url{http://pytest.org/latest/} -\end{frame} - -\begin{frame}[fragile]{pytest example} - -{\Large The same example -- with pytest} - -{\small -\begin{verbatim} -import random -import pytest - -seq = range(10) - -def test_shuffle(): - # make sure the shuffled sequence does not lose any elements - random.shuffle(seq) - seq.sort() - assert seq == range(10) - -def test_shuffle_immutable(): - pytest.raises(TypeError, random.shuffle, (1,2,3) ) -\end{verbatim} -} - -\end{frame} - -\begin{frame}[fragile]{pytest example (cont) } - -{\small -\begin{verbatim} -def test_choice(): - element = random.choice(seq) - assert (element in seq) - -def test_sample(): - for element in random.sample(seq, 5): - assert element in seq - -def test_sample_too_large(): - with pytest.raises(ValueError): - random.sample(seq, 20) -\end{verbatim} -} - -\vfill -(\verb|code/test_random_pytest.py|) - -\end{frame} - - -\begin{frame}[fragile]{Parameterized Tests} - -{\Large A whole set of inputs and outputs to test?} - -\vfill -{\Large \verb|pytest| has a nice way to do that (so does nose...)} - -\begin{verbatim} -import pytest -@pytest.mark.parametrize(("input", "expected"), [ - ("3+5", 8), - ("2+4", 6), - ("6*9", 42), -]) -def test_eval(input, expected): - assert eval(input) == expected -\end{verbatim} - -\url{http://pytest.org/latest/example/parametrize.html} - -\vfill -(\verb|code/test_pytest_parameter.py|) -\end{frame} - -\begin{frame}[fragile]{Test Coverage} - -{\LARGE \verb|coverage.py |} - -\vfill -{\Large Uses debugging hook to see which lines of code are actually executed --- plugins exist for most (all?) test runners} - -\vfill -{\Large \verb|pip install coverage |} - -\vfill -{\Large \verb|nosetests --with-coverage test_codingbat.py|} - -\vfill -\url{http://nedbatchelder.com/code/coverage/} -\end{frame} - -% -------------------------- -\begin{frame}[fragile]{Coding Bat} - -{\LARGE Coding Bat:} - -\url{http://codingbat.com/python} - - -\vfill -{\Large Tells you what unit tests to write:} - -\url{http://codingbat.com/prob/p118406} - -\vfill -{\Large We'll use them for our lab} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large First: get pip installed:} - -{\small \url{http://www.pip-installer.org/en/latest/installing.html} } - -\vfill -{\Large Second: install nose and/or pytest:} - -{\large \verb|pip install nose| -- \verb|pip install pytest|} - - -\vfill -{\Large Unit Testing:} - -\begin{itemize} - % \item unittest - % \begin{itemize} - % \item Pick a \url{codingbat.com} example - % \item Write a set of unit tests using \verb|unittest| - % (\verb|code\codingbat.py codingbat_unittest.py|) - % \end{itemize} - \item pytest / nose - \begin{itemize} - \item Test a \url{codingbat.com} with nose or pytest - \item Try doing test-driven development - (\verb|code\test_codingbat.py|) - \end{itemize} - - \item try running \verb|coverage| on your tests -\end{itemize} - -\end{frame} - - - -%------------------------------- -\begin{frame}[fragile]{Homework} - -Recommended Reading: -\begin{itemize} - \item TP: ch 15-18 - \item LPTHW: Ex 40 - 45 - \item Dive Into Python: chapter 4, 5 -\end{itemize} - -Do: -\begin{itemize} - \item Finish (or re-factor) the Labs you didn't finish in class. - \item Write some unit tests for a couple of the functions you've - written for previous excercises (Or something new) - \item Using the unit tests you jsut wrote, refactor the above functions - using list and/or dict comprehensions. - \item Write a script which does something useful (to you) and reads and writes - files. Very, very small scope is good. something useful at work would - be great, but no job secrets! - \item Start thinking about what you want to do for your project! -\end{itemize} - - -\end{frame} - - -\end{document} - - diff --git a/slides_sources/old_versions/week-05/presentation-week-05.toc b/slides_sources/old_versions/week-05/presentation-week-05.toc deleted file mode 100644 index 3f370542..00000000 --- a/slides_sources/old_versions/week-05/presentation-week-05.toc +++ /dev/null @@ -1,6 +0,0 @@ -\beamer@endinputifotherversion {3.10pt} -\beamer@sectionintoc {1}{Review/Questions}{3}{0}{1} -\beamer@sectionintoc {2}{Unicode}{6}{0}{2} -\beamer@sectionintoc {3}{Advanced Argument Passing}{17}{0}{3} -\beamer@sectionintoc {4}{List and Dict Comprehensions}{24}{0}{4} -\beamer@sectionintoc {5}{Unit Testing}{35}{0}{5} diff --git a/slides_sources/old_versions/week-05/presentation-week-05.vrb b/slides_sources/old_versions/week-05/presentation-week-05.vrb deleted file mode 100644 index f4e79f33..00000000 --- a/slides_sources/old_versions/week-05/presentation-week-05.vrb +++ /dev/null @@ -1,21 +0,0 @@ -\frametitle {Homework}\par Recommended Reading: -\begin{itemize} - \item TP: ch 15-18 - \item LPTHW: Ex 40 - 45 - \item Dive Into Python: chapter 4, 5 -\end{itemize} - -Do: -\begin{itemize} - \item Finish (or re-factor) the Labs you didn't finish in class. - \item Write some unit tests for a couple of the functions you've - written for previous excercises (Or something new) - \item Using the unit tests you jsut wrote, refactor the above functions - using list and/or dict comprehensions. - \item Write a script which does something useful (to you) and reads and writes - files. Very, very small scope is good. something useful at work would - be great, but no job secrets! - \item Start thinking about what you want to do for your project! -\end{itemize} - - diff --git a/slides_sources/old_versions/week-06/code/html_render/LAB_calling_code.html b/slides_sources/old_versions/week-06/code/html_render/LAB_calling_code.html deleted file mode 100644 index cf91da22..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/LAB_calling_code.html +++ /dev/null @@ -1,511 +0,0 @@ - - - - - - -Calling Code - - - -
        -

        Calling Code

        - -

        Code that can be used to call your html rendering classes

        -
        -

        Step 1

        -
        -page = Html()
        -
        -page.append("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text")
        -
        -
        -
        -

        Step 2

        -
        -page = Html()
        -
        -body = Body()
        -
        -body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text"))
        -
        -page.append(body)
        -
        -
        -
        -

        Step 3

        -
        -page = Html()
        -
        -head = Head()
        -head.append(Title("PythonClass = Revision 1087:"))
        -
        -page.append(head)
        -
        -body = Body()
        -
        -body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text"))
        -
        -page.append(body)
        -
        -
        -
        -

        Step 4

        -
        -page = Html()
        -
        -head = Head()
        -head.append(Title("PythonClass = Revision 1087:"))
        -
        -page.append(head)
        -
        -body = Body()
        -
        -body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text",
        -              style="text-align: center; font-style: oblique;"))
        -
        -page.append(body)
        -
        -
        -
        -

        Step 5

        -
        -page = Html()
        -
        -head = Head()
        -head.append(Title("PythonClass = Revision 1087:"))
        -
        -page.append(head)
        -
        -body = Body()
        -
        -body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text",
        -              style="text-align: center; font-style: oblique;"))
        -
        -body.append(Hr())
        -
        -page.append(body)
        -
        -
        -
        -

        Step 6

        -
        -page = Html()
        -
        -head = Head()
        -head.append(Title("PythonClass = Revision 1087:"))
        -
        -page.append(head)
        -
        -body = Body()
        -
        -body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text",
        -              style="text-align: center; font-style: oblique;"))
        -
        -body.append(Hr())
        -
        -body.append("And this is a ")
        -body.append( A("http://google.com", "link") )
        -body.append("to google")
        -
        -page.append(body)
        -
        -
        -
        -

        Step 7

        -
        -page = Html()
        -
        -head = Head()
        -head.append(Title("PythonClass = Revision 1087:"))
        -
        -page.append(head)
        -
        -body = Body()
        -
        -body.append(  H(2, "PythonClass - Class 6 example") )
        -
        -body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text",
        -              style="text-align: center; font-style: oblique;"))
        -
        -body.append(Hr())
        -
        -list = Ul(id="TheList", style="line-height:200%")
        -list.append( Li("The first item in a list") )
        -list.append( Li("This is the second item", style="color: red") )
        -item = Li()
        -item.append("And this is a ")
        -item.append( A("http://google.com", "link") )
        -item.append("to google")
        -list.append(item)
        -body.append(list)
        -
        -page.append(body)
        -
        -
        -
        -

        Step 8

        -
        -page = Html()
        -
        -head = Head()
        -head.append( Meta(charset="UTF-8") )
        -head.append(Title("PythonClass = Revision 1087:"))
        -
        -page.append(head)
        -
        -body = Body()
        -
        -body.append(  H(2, "PythonClass - Class 6 example") )
        -
        -body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough  to show that we can do some text",
        -              style="text-align: center; font-style: oblique;"))
        -
        -body.append(Hr())
        -
        -list = Ul(id="TheList", style="line-height:200%")
        -list.append( Li("The first item in a list") )
        -list.append( Li("This is the second item", style="color: red") )
        -item = Li()
        -item.append("And this is a ")
        -item.append( A("http://google.com", "link") )
        -item.append("to google")
        -list.append(item)
        -body.append(list)
        -
        -page.append(body)
        -
        -
        -
        - - diff --git a/slides_sources/old_versions/week-06/code/html_render/LAB_calling_code.rst b/slides_sources/old_versions/week-06/code/html_render/LAB_calling_code.rst deleted file mode 100644 index b8b0282c..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/LAB_calling_code.rst +++ /dev/null @@ -1,168 +0,0 @@ -Calling Code -############### - -Code that can be used to call your html rendering classes - -Step 1 --------- -:: - - page = Html() - - page.append("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text") - -Step 2 -------- -:: - - page = Html() - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text")) - - page.append(body) - -Step 3 ---------- -:: - - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text")) - - page.append(body) - -Step 4 ---------- -:: - - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - page.append(body) - -Step 5 ---------- -:: - - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - page.append(body) - -Step 6 ---------- -:: - - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - body.append("And this is a ") - body.append( A("http://google.com", "link") ) - body.append("to google") - - page.append(body) - -Step 7 ---------- -:: - - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append( H(2, "PythonClass - Class 6 example") ) - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - list = Ul(id="TheList", style="line-height:200%") - list.append( Li("The first item in a list") ) - list.append( Li("This is the second item", style="color: red") ) - item = Li() - item.append("And this is a ") - item.append( A("http://google.com", "link") ) - item.append("to google") - list.append(item) - body.append(list) - - page.append(body) - -Step 8 ---------- -:: - - page = Html() - - head = Head() - head.append( Meta(charset="UTF-8") ) - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append( H(2, "PythonClass - Class 6 example") ) - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - list = Ul(id="TheList", style="line-height:200%") - list.append( Li("The first item in a list") ) - list.append( Li("This is the second item", style="color: red") ) - item = Li() - item.append("And this is a ") - item.append( A("http://google.com", "link") ) - item.append("to google") - list.append(item) - body.append(list) - - page.append(body) diff --git a/slides_sources/old_versions/week-06/code/html_render/LAB_instuctions.html b/slides_sources/old_versions/week-06/code/html_render/LAB_instuctions.html deleted file mode 100644 index cf7c9a53..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/LAB_instuctions.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - -Instructions for html renderer exercise: - - - -
        -

        Instructions for html renderer exercise:

        - -
        -

        Goal:

        -

        A set of classes to render html pages. we'll try to get to all the features required to render:

        -
        -sample_html.html
        -
        -

        The exercise is broken down into a number of steps -- each requiring a bit more OO concepts in Python. WE will complete a step or two, then learn a bit more about OO in Python, then do a few more steps.

        -
        -
        -

        General Instructions:

        -

        For each step, add the required functionality. There is example code to run your code for each step in: LAB_calling_code.rst(html). You should be abel to run that code at each step, and then call the render() method to render your page. You may want to use sys.stdout to render to the terminal:

        -
        -import sys
        -....
        -page.render(sys.stdout)
        -
        -

        or you can use a regular file:

        -
        -outfile = open('test.html', 'w')
        -...
        -page.render(outfile)
        -
        -

        or use a cStringIO object (like a file, but in memory):

        -
        -import cStringIO
        -
        -...
        -
        -f = cStringIO.StringIO()
        -
        -page.render(f)
        -
        -# now print it to the screen:
        -f.reset()
        -print f.read()
        -
        -
        -
        -

        Solutions:

        -

        There are versions of the instructors' solution to each step in code/html_render/solutions, so you can look at a solution if you get stuck, But do try to figure it out yourself, first.

        -
        -
        -

        Step 1:

        -

        Create an Element class for rendering an html element (xml element).

        -

        It should have class attributes for the tag name ("html" first) and the indentation (spaces to indent for pretty printing)

        -

        The constructor signature should look like:

        -
        -Element(content=None)
        -
        -

        where content is a string

        -

        It should have an append method that can add another string to the content

        -

        It should have a render(file_out, ind = "") method that renders the tag -and the strings in the content.

        -

        file_out could be any file-like object (i.e have a write() method ).

        -

        ind is a string with the indentation level in it -- i.e the amount that the tag should be indented for pretty printing (maybe 4 spaces per level).

        -

        The amount of indentation should be set by the class attribute: indent

        -

        You can test with sys.stdout to print to the console, and/or use a -cStringIO.sStringIO object to store it in a string - or pass a file

        -

        You should now be able to render an html tag with text in it as contents.

        -
        -
        -

        Step 2:

        -

        Create a couple subclasses of Element, for a <body> tag and <p> tag. All you should have to do is override the tag class attribute (you may need to add a tag class attribute to the Element class...).

        -

        Now you can render a few different types of element.

        -

        Extend the Element.render() method so that it can render other elements -inside the tag in addition to strings. Simple recursion should -do it. i.e. it can call the render() method of the elements it contains.

        -

        Figure out a way to deal with the fact the the contents elements could be -either simple strings or Elements with render methods...(there are a few -ways to handle that...)

        -

        You should now be able to render a basic web page with an html tag around -the whole thing, and body tag inside, and multiple <p> tags inside that, -with text inside that.

        -
        -
        -

        Step 3:

        -

        Create a <head> element -- simple subclass.

        -

        Create a OneLineTag subclass of Element:

        -

        It should override the render method, to render everything on one line -- for the simple tags, like:

        -
        -<title> PythonClass - Class 6 example </title>
        -
        -

        Create a Title subclass of OneLineTag class for the title.

        -

        You should now be able to render an html doc with a head element, with a -title element in that, and a body element with some <P> elements and some text.

        -
        -
        -

        Step 4:

        -

        Extend the Element class to accept a set of attributes as keywords to the -constructor, ie.:

        -
        -Element("some text content", id="TheList", style="line-height:200%")
        -
        -

        ( remember **kwargs? )

        -

        The render method will need to be extended to render the attributes properly.

        -

        You can now render some <p> tags (and others) with attributes

        -
        -
        -

        Step 5:

        -

        Create a SelfClosingTag subclass of Element, to render tags like:

        -
        -<hr /> and <br /> (horizontal rule and line break).
        -
        -

        You will need to override the render method to render just the one tag and -attributes, if any.

        -

        Create a couple subclasses of SelfClosingTag for and <hr /> and <br />

        -
        -
        -

        Step 6:

        -

        Create a A class for an anchor (link) element. Its constructor should look like:

        -
        -A(self, link, content)
        -
        -

        where link is the link, and content is what you see. It can be called like so:

        -
        -A("http://google.com", "link")
        -
        -

        You should be able to subclass from Element, and only override the __init__ --- Calling the Element __init__ from the A __init__

        -

        You can now add a link to your web page.

        -
        -
        -

        Step 7:

        -

        Create Ul class for an unordered list (really simple subclass of Element)

        -

        Create Li class for an element in a list (also really simple)

        -

        Add a list to your web page.

        -

        Create a Header class -- this one should take an integer argument for the -header level. i.e <h1>, <h2>, <h3>, called like:

        -
        -H(2, "The text of the header") for an <h2> header
        -
        -

        It can subclass from OneLineTag -- overriding the __init__, then calling the superclass __init__

        -
        -
        -

        Step 8:

        -

        Update the Html element class to render the "<!DOCTYPE html>" tag at the -head of the page, before the html element.

        -

        You can do this by subclassing Element, overriding render(), but then -calling the Element render from the new render.

        -

        Create a subclass of SelfClosingTag for <meta charset="UTF-8" /> (like -for <hr /> and <br /> and add the meta element to the beginning of -the head element to give your document an encoding.

        -

        The doctype and encoding are HTML 5 and you can check this at: -http://validator.w3.org.

        -

        You now have a pretty full-featured html renderer -- play with it, add some -new tags, etc....

        -
        -
        - - diff --git a/slides_sources/old_versions/week-06/code/html_render/LAB_instuctions.rst b/slides_sources/old_versions/week-06/code/html_render/LAB_instuctions.rst deleted file mode 100644 index 4c87d25e..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/LAB_instuctions.rst +++ /dev/null @@ -1,190 +0,0 @@ - -Instructions for html renderer exercise: -########################################### - -Goal: -====== - -A set of classes to render html pages. we'll try to get to all the features required to render:: - - sample_html.html - -The exercise is broken down into a number of steps -- each requiring a bit more OO concepts in Python. WE will complete a step or two, then learn a bit more about OO in Python, then do a few more steps. - -General Instructions: -====================== - -For each step, add the required functionality. There is example code to run your code for each step in: ``LAB_calling_code.rst(html)``. You should be abel to run that code at each step, and then call the ``render()`` method to render your page. You may want to use sys.stdout to render to the terminal:: - - import sys - .... - page.render(sys.stdout) - -or you can use a regular file:: - - outfile = open('test.html', 'w') - ... - page.render(outfile) - -or use a cStringIO object (like a file, but in memory):: - - import cStringIO - - ... - - f = cStringIO.StringIO() - - page.render(f) - - # now print it to the screen: - f.reset() - print f.read() - -Solutions: -============ - -There are versions of the instructors' solution to each step in ``code/html_render/solutions``, so you can look at a solution if you get stuck, But do try to figure it out yourself, first. - - -Step 1: -========= - -Create an ``Element`` class for rendering an html element (xml element). - -It should have class attributes for the tag name ("html" first) and the indentation (spaces to indent for pretty printing) - -The constructor signature should look like:: - - Element(content=None) - -where ``content`` is a string - -It should have an ``append`` method that can add another string to the content - -It should have a ``render(file_out, ind = "")`` method that renders the tag -and the strings in the content. - -``file_out`` could be any file-like object (i.e have a ``write()`` method ). - -``ind`` is a string with the indentation level in it -- i.e the amount that the tag should be indented for pretty printing (maybe 4 spaces per level). - -The amount of indentation should be set by the class attribute: ``indent`` - -You can test with ``sys.stdout`` to print to the console, and/or use a -``cStringIO.sStringIO`` object to store it in a string - or pass a file - -You should now be able to render an html tag with text in it as contents. - -Step 2: -========== - -Create a couple subclasses of ``Element``, for a tag and

        tag. All you should have to do is override the ``tag`` class attribute (you may need to add a ``tag`` class attribute to the Element class...). - -Now you can render a few different types of element. - -Extend the ``Element.render()`` method so that it can render other elements -inside the tag in addition to strings. Simple recursion should -do it. i.e. it can call the ``render()`` method of the elements it contains. - -Figure out a way to deal with the fact the the contents elements could be -either simple strings or Elements with render methods...(there are a few -ways to handle that...) - -You should now be able to render a basic web page with an html tag around -the whole thing, and body tag inside, and multiple

        tags inside that, -with text inside that. - -Step 3: -========== - -Create a element -- simple subclass. - -Create a ``OneLineTag`` subclass of ``Element``: - -It should override the render method, to render everything on one line -- for the simple tags, like:: - - PythonClass - Class 6 example - -Create a ``Title`` subclass of ``OneLineTag`` class for the title. - -You should now be able to render an html doc with a head element, with a -title element in that, and a body element with some

        elements and some text. - -Step 4: -=========== - -Extend the ``Element`` class to accept a set of attributes as keywords to the -constructor, ie.:: - - Element("some text content", id="TheList", style="line-height:200%") - -( remember ``**kwargs``? ) - -The render method will need to be extended to render the attributes properly. - -You can now render some

        tags (and others) with attributes - -Step 5: -======== - -Create a ``SelfClosingTag`` subclass of Element, to render tags like:: - -


        and
        (horizontal rule and line break). - -You will need to override the render method to render just the one tag and -attributes, if any. - -Create a couple subclasses of ``SelfClosingTag`` for and
        and
        - -Step 6: -========== - -Create a ``A`` class for an anchor (link) element. Its constructor should look like:: - - A(self, link, content) - -where link is the link, and content is what you see. It can be called like so:: - - A("http://google.com", "link") - -You should be able to subclass from ``Element``, and only override the ``__init__`` --- Calling the ``Element`` ``__init__`` from the ``A __init__`` - -You can now add a link to your web page. - -Step 7: -=========== - -Create ``Ul`` class for an unordered list (really simple subclass of ``Element``) - -Create ``Li`` class for an element in a list (also really simple) - -Add a list to your web page. - -Create a ``Header`` class -- this one should take an integer argument for the -header level. i.e

        ,

        ,

        , called like:: - - H(2, "The text of the header") for an

        header - -It can subclass from ``OneLineTag`` -- overriding the ``__init__``, then calling the superclass ``__init__`` - -Step 8: -========== - -Update the ``Html`` element class to render the "" tag at the -head of the page, before the html element. - -You can do this by subclassing ``Element``, overriding ``render()``, but then -calling the ``Element`` render from the new render. - -Create a subclass of ``SelfClosingTag`` for (like -for
        and
        and add the meta element to the beginning of -the head element to give your document an encoding. - -The doctype and encoding are HTML 5 and you can check this at: -http://validator.w3.org. - -You now have a pretty full-featured html renderer -- play with it, add some -new tags, etc.... - - - \ No newline at end of file diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_1.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_1.py deleted file mode 100755 index 909631e8..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_1.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -This is the first Element base class --- - -""" - -class Element(object): - """ - An element with multiple items in the content - """ - tag = "html" - indent = " " - def __init__(self, content=None): - """ - initialize an element and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - file_out.write(">") - for child in self.children: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(child) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - - -if __name__ == "__main__": - import sys, cStringIO - page = Element() - - page.append("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text") - - page.append("And here is another piece of text -- you should be able to add any number") - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_2.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_2.py deleted file mode 100755 index 9339f529..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_2.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -This adds a couple sub-classes - -""" - -class Element(object): - """ - An element with multiple items in the content - """ - tag = "" - indent = " " - def __init__(self, content=None): - """ - initialize an element and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - file_out.write(">") - for child in self.children: - try: - child.render(file_out, ind + self.indent) - except AttributeError: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(str(child)) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - -class Html(Element): - tag = "html" - -class Body(Element): - tag = "body" - -class P(Element): - tag = "p" - - -if __name__ == "__main__": - import sys, cStringIO - page = Html() - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text")) - - page.append(body) - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_3.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_3.py deleted file mode 100755 index efc77914..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_3.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -over-riding a method... - -""" - -class Element(object): - """ - An element with multiple items in the content - """ - tag = "" - indent = " " - def __init__(self, content=None): - """ - initialize an element and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - file_out.write(">") - for child in self.children: - try: - child.render(file_out, ind + self.indent) - except AttributeError: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(str(child)) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - -class Html(Element): - tag = "html" - -class Head(Element): - tag = "head" - -class Body(Element): - tag = "body" - -class P(Element): - tag = "p" - -class OneLineTag(Element): - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - file_out.write(">") - for child in self.children: - try: - child.render(file_out) - except AttributeError: - file_out.write(str(child)) - file_out.write(''%self.tag) - -class Title(OneLineTag): - tag = "title" - - -if __name__ == "__main__": - import sys, cStringIO - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text")) - - page.append(body) - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_4.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_4.py deleted file mode 100755 index 7712bcc6..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_4.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -Add the ability to handle tag attributes. - -""" - -class Element(object): - """ - An element with optional attributes and multiple items in the content - """ - tag = "" - indent = " " - def __init__(self, content=None, **attributes): - """ - initialize an element with optional attributes, and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - :param [attributes]: optional attributes as keyword parameters. - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - self.attributes = attributes - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out, ind + self.indent) - except AttributeError: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(str(child)) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - -class Html(Element): - tag = "html" - -class Head(Element): - tag = "head" - -class Body(Element): - tag = "body" - -class P(Element): - tag = "p" - -class OneLineTag(Element): - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out) - except AttributeError: - file_out.write(str(child)) - file_out.write(''%self.tag) - -class Title(OneLineTag): - tag = "title" - - -if __name__ == "__main__": - import sys, cStringIO - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - page.append(body) - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_5.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_5.py deleted file mode 100755 index a45b8168..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_5.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -Overriding render() again -- and a few more sub-classes. - -""" - -class Element(object): - """ - An element with optional attributes and multiple items in the content - """ - tag = "" - indent = " " - def __init__(self, content=None, **attributes): - """ - initialize an element with optional attributes, and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - :param [attributes]: optional attributes as keyword parameters. - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - self.attributes = attributes - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out, ind + self.indent) - except AttributeError: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(str(child)) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - -class Html(Element): - tag = "html" - -class Head(Element): - tag = "head" - -class Body(Element): - tag = "body" - -class P(Element): - tag = "p" - -class SelfClosingTag(Element): - """ - Element with a single tag -- no content, only attributes - """ - def __init__(self, **attributes): - self.attributes = attributes - - def render(self, file_out, ind = ""): - """ - an html rendering method for self-closing elements: - attributes, but no content a no closing tag - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(" />") - -class Hr(SelfClosingTag): - tag = "hr" - -class OneLineTag(Element): - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out) - except AttributeError: - file_out.write(str(child)) - file_out.write(''%self.tag) - -class Title(OneLineTag): - tag = "title" - - -if __name__ == "__main__": - import sys, cStringIO - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - page.append(body) - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_6.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_6.py deleted file mode 100755 index 2fe56ff1..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_6.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -Overriding __init__, and calling superclass __init__ - -""" - -class Element(object): - """ - An element with optional attributes and multiple items in the content - """ - tag = "" - indent = " " - def __init__(self, content=None, **attributes): - """ - initialize an element with optional attributes, and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - :param [attributes]: optional attributes as keyword parameters. - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - self.attributes = attributes - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out, ind + self.indent) - except AttributeError: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(str(child)) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - -class Html(Element): - tag = "html" - -class Head(Element): - tag = "head" - -class Body(Element): - tag = "body" - -class P(Element): - tag = "p" - -class SelfClosingTag(Element): - """ - Element with a single tag -- no content, only attributes - """ - def __init__(self, **attributes): - self.attributes = attributes - - def render(self, file_out, ind = ""): - """ - an html rendering method for self-closing elements: - attributes, but no content a no closing tag - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(" />") - -class Hr(SelfClosingTag): - tag = "hr" - -class OneLineTag(Element): - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out) - except AttributeError: - file_out.write(str(child)) - file_out.write(''%self.tag) - -class Title(OneLineTag): - tag = "title" - -class A(OneLineTag): - """ - element for a link ( tag ) - """ - tag = "a" - def __init__(self, link, content): - OneLineTag.__init__(self, content, href=link) - - -if __name__ == "__main__": - import sys, cStringIO - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - body.append("And this is a ") - body.append( A("http://google.com", "link") ) - body.append("to google") - - page.append(body) - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_7.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_7.py deleted file mode 100755 index 432cab2f..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_7.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -Subclassing and a new __init__ - -""" - -class Element(object): - """ - An element with optional attributes and multiple items in the content - """ - tag = "" - indent = " " - def __init__(self, content=None, **attributes): - """ - initialize an element with optional attributes, and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - :param [attributes]: optional attributes as keyword parameters. - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - self.attributes = attributes - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out, ind + self.indent) - except AttributeError: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(str(child)) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - -class Html(Element): - tag = "html" - -class Head(Element): - tag = "head" - -class Body(Element): - tag = "body" - -class P(Element): - tag = "p" - -class Ul(Element): - """ - element for an unordered list - """ - tag = "ul" - -class Li(Element): - """ - element for the item in a list - """ - tag = "li" - -class SelfClosingTag(Element): - """ - Element with a single tag -- no content, only attributes - """ - def __init__(self, **attributes): - self.attributes = attributes - - def render(self, file_out, ind = ""): - """ - an html rendering method for self-closing elements: - attributes, but no content a no closing tag - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(" />") - -class Hr(SelfClosingTag): - tag = "hr" - -class OneLineTag(Element): - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out) - except AttributeError: - file_out.write(str(child)) - file_out.write(''%self.tag) - -class Title(OneLineTag): - tag = "title" - -class A(OneLineTag): - """ - element for a link ( tag ) - """ - tag = "a" - def __init__(self, link, content): - OneLineTag.__init__(self, content, href=link) - -class H(OneLineTag): - """ - class for header tags, the level is specified in a parameter - - """ - def __init__(self, level, content, **attributes): - OneLineTag.__init__(self, content, **attributes) - - self.tag = "h%i"%level - - -if __name__ == "__main__": - import sys, cStringIO - page = Html() - - head = Head() - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append( H(2, "PythonClass - Class 6 example") ) - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - list = Ul(id="TheList", style="line-height:200%") - list.append( Li("The first item in a list") ) - list.append( Li("This is the second item", style="color: red") ) - item = Li() - item.append("And this is a ") - item.append( A("http://google.com", "link") ) - item.append("to google") - list.append(item) - body.append(list) - - page.append(body) - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_8.py b/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_8.py deleted file mode 100755 index a04592e0..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/Solutions/gen_8.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python - -""" -Python class example. - -Overriding render(), but calling the superclass render, too. - -""" - -class Element(object): - """ - An element with optional attributes and multiple items in the content - """ - tag = "" - indent = " " - def __init__(self, content=None, **attributes): - """ - initialize an element with optional attributes, and any number of sub-elements and content - - :param content: content of the element: single string or another element. - an empty string will be ignored - :param [attributes]: optional attributes as keyword parameters. - - example: - """ - if not content: - self.children = [] - else: - self.children = [content] - - self.attributes = attributes - - def append(self, element): - self.children.append(element) - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out, ind + self.indent) - except AttributeError: - file_out.write("\n") - file_out.write(ind + self.indent) - file_out.write(str(child)) - file_out.write("\n") - file_out.write(ind) - file_out.write(''%self.tag) - -class Html(Element): - tag = "html" - - ## override the render method to add the "" - def render(self, file_out, ind = ""): - file_out.write("") - # call the superclass render: - Element.render(self, file_out, ind) - -class Head(Element): - tag = "head" - -class Body(Element): - tag = "body" - -class P(Element): - tag = "p" - -class Ul(Element): - """ - element for an unordered list - """ - tag = "ul" - -class Li(Element): - """ - element for the item in a list - """ - tag = "li" - -class SelfClosingTag(Element): - """ - Element with a single tag -- no content, only attributes - """ - def __init__(self, **attributes): - self.attributes = attributes - - def render(self, file_out, ind = ""): - """ - an html rendering method for self-closing elements: - attributes, but no content a no closing tag - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(" />") - -class Meta(SelfClosingTag): - tag = "meta" - -class Hr(SelfClosingTag): - tag = "hr" - -class OneLineTag(Element): - - def render(self, file_out, ind = ""): - """ - an html rendering method for elements that have attributes and content - """ - file_out.write("\n") - file_out.write(ind) - file_out.write("<%s"%self.tag) - for key, value in self.attributes.items(): - file_out.write(' %s="%s"'%(key, value) ) - file_out.write(">") - for child in self.children: - try: - child.render(file_out) - except AttributeError: - file_out.write(str(child)) - file_out.write(''%self.tag) - -class Title(OneLineTag): - tag = "title" - -class A(OneLineTag): - """ - element for a link ( tag ) - """ - tag = "a" - def __init__(self, link, content): - OneLineTag.__init__(self, content, href=link) - -class H(OneLineTag): - """ - class for header tags, the level is specified in a parameter - - """ - def __init__(self, level, content, **attributes): - OneLineTag.__init__(self, content, **attributes) - - self.tag = "h%i"%level - - -if __name__ == "__main__": - import sys, cStringIO - page = Html() - - head = Head() - head.append( Meta(charset="UTF-8") ) - head.append(Title("PythonClass = Revision 1087:")) - - page.append(head) - - body = Body() - - body.append( H(2, "PythonClass - Class 6 example") ) - - body.append(P("Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text", - style="text-align: center; font-style: oblique;")) - - body.append(Hr()) - - list = Ul(id="TheList", style="line-height:200%") - list.append( Li("The first item in a list") ) - list.append( Li("This is the second item", style="color: red") ) - item = Li() - item.append("And this is a ") - item.append( A("http://google.com", "link") ) - item.append("to google") - list.append(item) - body.append(list) - - page.append(body) - - f = cStringIO.StringIO() - - page.render(f) - - f.reset() - print f.read() - - f.reset() - open("test_html.html", 'w').write(f.read()) diff --git a/slides_sources/old_versions/week-06/code/html_render/sample_html.html b/slides_sources/old_versions/week-06/code/html_render/sample_html.html deleted file mode 100644 index fc71d497..00000000 --- a/slides_sources/old_versions/week-06/code/html_render/sample_html.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - PythonClass = Revision 1087: - - -

        PythonClass - OOP example

        -

        - Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text -

        -
        -
        - - diff --git a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.html b/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.html deleted file mode 100644 index e10a07ca..00000000 --- a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.html +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - -lambda and keyword evaluation excercise - - - -
        -

        lambda and keyword evaluation excercise

        - -
        -

        The challenge:

        -

        Write a function that returns a list of n functions, -such that each one, when called, will return the input value, -incremented by an increasing number.

        -

        You should use a for loop, lambda, and a keyword argument

        -

        Not clear? here's what you should get:

        -
        -    In [96]: the_list = function_builder(4)
        -### so the_list should contain n functions (callables)
        -
        -    In [97]: the_list[0](2)
        -    Out[97]: 2
        -## the zeroth element of the list is a function that add 0
        -## to the input, hence called with 2, returns 2
        -
        -    In [98]: the_list[1](2)
        -    Out[98]: 3
        -    ## the 1st element of the list is a function that adds 1
        -    ## to the input value, thus called with 2, returns 3
        -
        -    In [100]: for f in the_list:
        -        print f(5)
        -       .....:
        -    5
        -    6
        -    7
        -    8
        -### If you loop through them all, and call them, each one adds one more to the input, 5... i.e. the nth function in the list adds n to the input.
        -
        -
        -
        -

        Extra credit:

        -

        Do it with a list comprhension, instead of a for loop

        -
        -
        -

        TDD:

        -

        In lambda_keyword.py, there is a function defined:

        -
        -def function_builder(n):
        -    ## put something in here...
        -    pass
        -
        -
        -
        Clearly, it does nothing. However in test_lambda_keyword.py there are some tests -- you can run them, but they will fail::
        -

        $ py.test test_lambda_keyword.py -... -... -> assert func_list[0](12) == 12 -E TypeError: 'NoneType' object has no attribute '__getitem__'

        -

        test_lambda_keyword.py:42: TypeError -=========================== 3 failed in 0.04 seconds ===============

        -
        -
        -

        Your goal is to fill in that funciton so that those tests pass.

        -
        -
        -

        "Cheating"

        -

        Note that those tests only test a few things, and with small values -- so you could pretty easily hard-code a bunch of stuff to make them pass -- but what's the fun of that?

        -

        This is eveidence that "full test coverage" is a fantasy!

        -
        -
        - - diff --git a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.py b/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.py deleted file mode 100644 index 2f8b5002..00000000 --- a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -""" -example code for using lambda, keywords, and keyword scope - -The challenge: - -Write a function that returns a list of n functions, -such that each one, when called, will return the input value, -incremented by an increaseing number. - -you should use a for loop, lambda, and a keyword argument - -Not clear? here's what you should get: - -In [96]: the_list = function_builder(4) - -In [97]: the_list[0](2) -Out[97]: 2 - -In [98]: the_list[1](2) -Out[98]: 3 - -In [100]: for f in the_list: - print f(5) - .....: -5 -6 -7 -8 - -extra credit: do it with a list comprhension, instead of a for loop - -""" - -def function_builder(n): - ## put somethingin here... - pass diff --git a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.pyc b/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.pyc deleted file mode 100644 index 1922e355..00000000 Binary files a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.pyc and /dev/null differ diff --git a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.rst b/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.rst deleted file mode 100644 index 26eea762..00000000 --- a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword.rst +++ /dev/null @@ -1,74 +0,0 @@ -lambda and keyword evaluation excercise -######################################### - - -The challenge: -================= - -Write a function that returns a list of n functions, -such that each one, when called, will return the input value, -incremented by an increasing number. - -You should use a for loop, lambda, and a keyword argument - -Not clear? here's what you should get:: - - In [96]: the_list = function_builder(4) - ### so the_list should contain n functions (callables) - - In [97]: the_list[0](2) - Out[97]: 2 - ## the zeroth element of the list is a function that add 0 - ## to the input, hence called with 2, returns 2 - - In [98]: the_list[1](2) - Out[98]: 3 - ## the 1st element of the list is a function that adds 1 - ## to the input value, thus called with 2, returns 3 - - In [100]: for f in the_list: - print f(5) - .....: - 5 - 6 - 7 - 8 - ### If you loop through them all, and call them, each one adds one more to the input, 5... i.e. the nth function in the list adds n to the input. - - -Extra credit: -================ - -Do it with a list comprhension, instead of a for loop - -TDD: -========== - -In lambda_keyword.py, there is a function defined:: - - - def function_builder(n): - ## put something in here... - pass - -Clearly, it does nothing. However in test_lambda_keyword.py there are some tests -- you can run them, but they will fail:: - - $ py.test test_lambda_keyword.py - ... - ... - > assert func_list[0](12) == 12 - E TypeError: 'NoneType' object has no attribute '__getitem__' - - test_lambda_keyword.py:42: TypeError - =========================== 3 failed in 0.04 seconds =============== - - -Your goal is to fill in that funciton so that those tests pass. - -"Cheating" -============= - -Note that those tests only test a few things, and with small values -- so you could pretty easily hard-code a bunch of stuff to make them pass -- but what's the fun of that? - -This is eveidence that "full test coverage" is a fantasy! - diff --git a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword_solution.py b/slides_sources/old_versions/week-06/code/lambda/lambda_keyword_solution.py deleted file mode 100644 index 5ecd790b..00000000 --- a/slides_sources/old_versions/week-06/code/lambda/lambda_keyword_solution.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python - -""" -example code for using lambda, keywords, and keyword scope - - -The challenge: - -Write a function that returns a list of n functions, -such that each one, when called, will return the input value, -incremented by an increaseing number. - -you should use a for loop, lambda, and a keyword argument - -extra credit: do it with a list comprhension, instead of a for loop - -""" - -def function_builder(n): - - l = [] - for i in range(n): - l.append( lambda x, i=i: x+i ) - return l - -def function_builder2(n): - - return [ lambda x, i=i: x+i for i in range(n) ] - diff --git a/slides_sources/old_versions/week-06/code/lambda/test_lambda_keyword.py b/slides_sources/old_versions/week-06/code/lambda/test_lambda_keyword.py deleted file mode 100644 index 038f2e6e..00000000 --- a/slides_sources/old_versions/week-06/code/lambda/test_lambda_keyword.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python - -""" -unit tests for the lambda_keyword excercise -""" - -from lambda_keyword import function_builder -#from lambda_keyword_solution import function_builder - -def test_length(): - """ - the function should return a list of the length input - """ - assert len(function_builder(0)) == 0 - - assert len(function_builder(3)) == 3 - - assert len(function_builder(5)) == 5 - -def test_result(): - """ - the functions in the list should increment the input values - """ - func_list = function_builder(5) - - assert func_list[0](3) == 3 - - assert func_list[1](3) == 4 - - assert func_list[2](3) == 5 - - assert func_list[3](3) == 6 - -def test_result2(): - """ - the functions in the list should increment the input values - - same test as above, but with different values - """ - func_list = function_builder(10) - - assert func_list[0](12) == 12 - - assert func_list[1](10) == 11 - - assert func_list[9](3) == 12 - - - - diff --git a/slides_sources/old_versions/week-06/code/simple_classes.py b/slides_sources/old_versions/week-06/code/simple_classes.py deleted file mode 100644 index 16fe2f5d..00000000 --- a/slides_sources/old_versions/week-06/code/simple_classes.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python -""" -simple_classes.py - -demonstrating the basics of a class -""" - -## create a point class -class Point(object): - def __init__(self, x, y): - self.x = x - self.y = y - -## create an instance of that class -p = Point(3,4) - -## access the attributes -print "p.x is:", p.x -print "p.y is:", p.y - -class Point2(object): - size = 4 - color= "red" - def __init__(self, x, y): - self.x = x - self.y = y - -p2 = Point2(4,5) -print p2.size -print p2.color - -class Point3(object): - size = 4 - color= "red" - def __init__(self, x, y): - self.x = x - self.y = y - def get_color(self): - return self.color - - -p3 = Point3(4,5) -print p3.size -print p3.get_color() - -class Circle(object): - color = "red" - def __init__(self, diameter): - self.diameter = diameter - - def grow(self, factor=2): - """ - grows the circle's diameter - - :param factor=2: factor by which to grow the circle - """ - self.diameter = self.diameter * factor - - def get_area(self): - return math.pi * self.diameter / 2.0 - -class NewCircle(Circle): - color = "blue" - - def grow(self, factor=2): - """grows the area by factor...""" - self.diameter = self.diameter * math.sqrt(2) - -nc = NewCircle -print nc.color - -class CircleR(Circle): - def __init__(self, radius): - diameter = radius*2 - Circle.__init__(self, diameter) - -class CircleR2(Circle): - def __init__(self, radius): - self.radius = radius - - def get_area(self): - return Circle.get_area(self, self.radius*2) - - diff --git a/slides_sources/old_versions/week-06/presentation-week-06.pdf b/slides_sources/old_versions/week-06/presentation-week-06.pdf deleted file mode 100644 index e40ce7c2..00000000 Binary files a/slides_sources/old_versions/week-06/presentation-week-06.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-06/presentation-week-06.tex b/slides_sources/old_versions/week-06/presentation-week-06.tex deleted file mode 100644 index f4a80da7..00000000 --- a/slides_sources/old_versions/week-06/presentation-week-06.tex +++ /dev/null @@ -1,958 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Intro to Python: Week 1]{Introduction to Python\\ -Lambda, Functional Programming and intro to OO} -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{November 5, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -% \renewcommand{\baselinestretch}{1.2} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - - -\section{Review/Questions} - -% --------------------------------------------- -\begin{frame}{Review of Previous Class} - -\begin{itemize} - \item Unicode? - \item Keyword arguments? - \item Comprehensions? - \item Unit testing? -\end{itemize} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning talks today:} - -\vfill -{\Large -Lawrence Chan - -\vfill -Kimberly Colwell - -\vfill -Maria Petrova - - -} -\vfill - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Homework review} - - \vfill - {\Large Homework Questions? } - - \vfill - -\end{frame} - -%######################## -\section{Lambda} - -% --------------------------------------------- -\begin{frame}[fragile]{lambda} - -{\Large``Anonymous'' functions} - -\vfill -\begin{verbatim} -In [171]: f = lambda x, y: x+y - -In [172]: f(2,3) -Out[172]: 5 -\end{verbatim} - -\vfill -{\Large Can only be an expression -- not a statement} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{lambda} - -{\Large Called ``Anonymous'': it doesn't need a name.} - -\vfill -{\Large It's a python object, it can be stored in a list or other container} - -\vfill -\begin{verbatim} -In [7]: l = [lambda x, y: x+y] -In [8]: type(l[0]) -Out[8]: function -\end{verbatim} - -\vfill -{\Large And you can call it:} - -\vfill -\begin{verbatim} -In [9]: l[0](3,4) -Out[9]: 7 -\end{verbatim} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{functions as first class objects} - -{\Large You can do that with ``regular'' functions too:} - -\vfill -\begin{verbatim} -In [12]: def fun(x,y): - ....: return x+y - ....: - -In [13]: l = [fun] - -In [14]: type(l[0]) -Out[14]: function - -In [15]: l[0](3,4) -Out[15]: 7 -\end{verbatim} - -\end{frame} - -\section{Functional Programming} - -% --------------------------------------------- -\begin{frame}[fragile]{map} - -{\Large \verb|map| ``maps'' a function onto a sequence of objects -- -It applies the function to each item in the list, returning another list} - -\begin{verbatim} -In [23]: l = [2, 5, 7, 12, 6, 4] -In [24]: def fun(x): - return x*2 + 10 - -In [25]: map(fun, l) -Out[25]: [14, 20, 24, 34, 22, 18] -\end{verbatim} - -{\Large But if you only need that function once:} -\begin{verbatim} -In [26]: map(lambda x: x*2 + 10, l) -Out[26]: [14, 20, 24, 34, 22, 18] -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{filter} - -{\Large \verb|filter| ``filters'' a sequence of objects with a boolean function -- -It keeps only those for which the function is True -} - -\vfill -{\Large To get only the even numbers} - -\begin{verbatim} -In [27]: l = [2, 5, 7, 12, 6, 4] - -In [28]: filter(lambda x: not x%2, l) -Out[28]: [2, 12, 6, 4] -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{reduce} - -{\Large \verb|reduce| ``reduces'' a sequence of objects to a single object with a function that combines two arguments} - -\vfill -{\Large To get the sum:} - -\begin{verbatim} -In [30]: l = [2, 5, 7, 12, 6, 4] - -In [31]: reduce(lambda x,y: x+y, l) -Out[31]: 36 -\end{verbatim} - -{\Large To get the product:} - -\begin{verbatim} -In [32]: reduce(lambda x,y: x*y, l) -Out[32]: 20160 -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{comprehensions} - -{\Large Couldn't you do all this with comprehensions?} - -\vfill -{\LARGE Yes:} -\begin{verbatim} -In [33]: [x+2 + 10 for x in l] -Out[33]: [14, 17, 19, 24, 18, 16] - -In [34]: [x for x in l if not x%2] -Out[34]: [2, 12, 6, 4] -\end{verbatim} - -{\Large Except Reduce} - -\vfill -But Guido thinks almost all uses of reduce are really \verb|sum()| -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{functional programming} - -\vfill -{\Large Comprehensions and map, filter, reduce are all ``functional programming'' approaches} - -\vfill -{\Large \verb|map, filter| and \verb|reduce| pre-date comprehensions in Python's history} - -\vfill -{\Large Some people like that syntax better} - -\vfill -{\Large And ``map-reduce'' is a big concept these days for parallel processing of ``Big Data'' in NoSQL databases.} - -\vfill -{\Large (Hadoop, MongoDB, etc.) } - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{lambda} - -{\Large Can also use keyword arguments} - -\begin{verbatim} -In [186]: l = [] -In [187]: for i in range(3): - l.append(lambda x, e=i: x**e) - .....: -In [189]: for f in l: - print f(3) -1 -3 -9 -\end{verbatim} - -{\Large Note when the keyword argument is evaluated: this turns out to be handy} - -\end{frame} -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\large -\vfill -\begin{itemize} - \item Write a function that returns a list of n functions, -such that each one, when called, will return the input value, -incremented by an increasing number. - - \item Use a for loop, \verb|lambda|, and a keyword argument -\end{itemize} - -\vfill -\verb|code/lambda/lambda_keyword.html(rst)| \\ -\verb|code/lambda/lambda_keyword.py| \\ -\verb|code/lambda/test_lambda_keyword.py| \\ -} - -\end{frame} - - - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -{\l\Large -\vfill -Lawrence Chan - -\vfill -Kimberly Colwell - -} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Object Oriented Programming} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill - {\Large More about Python implementation than OO design/strengths/weaknesses} - -\vfill -{\Large One reason for this:\\ -Folks can't even agree on what OO ``really`` means} - -\vfill -The Quarks of Object-Oriented Development - Deborah J. Armstrong:\\ -\url{http://agp.hx0.ru/oop/quarks.pdf} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill - {\LARGE Is Python a ``True'' Object-Oriented Language?} - -\vfill -{\Large (Doesn't support full encapsulation, doesn't require -objects, etc...)} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill - {\LARGE I don't Care!} - -\vfill -{\Large Good software design is about code re-use, clean separation of concerns, -refactorability, testability, etc...} - -\vfill -{\Large OO can help with all that, but: -\begin{itemize} - \item It doesn't guarantee it - \item It can get in the way -\end{itemize} -} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill - {\LARGE Python is a Dynamic Language} - -\vfill -{\Large That clashes with ``pure'' OO} - -\vfill -{\Large Think in terms of what makes sense for your project - - -- not any one paradigm of software design. -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill - {\LARGE OO for this class:} - -\vfill -{\Large -``Objects can be thought of as wrapping their data \\[.03in] -within a set of functions designed to ensure that \\[.03in] -the data are used appropriately, and to assist in \\[.03in] -that use`` -} - -\vfill -{\small -\url{http://en.wikipedia.org/wiki/Object-oriented_programming} -} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill -{\LARGE Even simpler:} - -\vfill -{\Large -Objects are data and the functions that act on them in one place. -} - -\vfill -{\Large -In Python: just another namespace. -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill -{\LARGE The OO buzzwords: - -\vfill -\begin{itemize} - \item data abstraction - \item encapsulation - \item modularity - \item polymorphism - \item inheritance -\end{itemize} -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill -{\LARGE You can do OO in C} - -(see the GTK+ project) - -\vfill -{\Large -``OO languages'' give you some handy tools to make it easier (and safer): -} - -\vfill -{\Large -\begin{itemize} - \item polymorphism (duck typing gives you this anyway) - \item inheritance -\end{itemize} -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill -{\Large OO is the dominant model for the past couple decades - -\vfill -You will need to use it: - -\vfill --- It's a good idea for a lot of problems - -\vfill --- You'll need to work with OO packages -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Object Oriented Programming} - -\vfill -{\LARGE Some definitions} - -\begin{description} - \item[class] A category of objects: particular data and behavior: A ``circle'' (same as a type in python) - \item[instance] A particular object of a class: a specific circle - \item[object] The general case of a instance -- really any value\\ (in Python anyway) - \item[attribute] Something that belongs to an object (or class) - -- generally thought of as a variable, or single object, as opposed to a ... - \item[method] A function that belongs to a class -\end{description} - -\end{frame} - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Python Classes} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\Large The \verb|class| statement} - -\vfill -{\large \verb|class| creates a new type object:} - -\begin{verbatim} -In [4]: class C(object): - pass - ...: -In [5]: type(C) -Out[5]: type -\end{verbatim} - -{\large It is created when the statement is run -- much like \verb|def|} - -\vfill -(note on``new style'' classes) - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\Large Note about the book (TP):} - -Chapters 15 and 16 use a style that generally isn't recommended: - -\begin{verbatim} -In [6]: class Point(object): - ...: pass -In [7]: p = Point() -In [8]: p.x = 4 -In [9]: p.y = 2 -\end{verbatim} - -Python is Dynamic -- you can do this, but you generally want more structure, -defaults, etc. - -\vfill -(it used to be a quick and dirty "struct"\\ -\hspace{0.2in} -- but use a named tuple now) -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\Large About the simplest class:} - -\begin{verbatim} ->>> class Point(object): -... x = 1 -... y = 2 ->>> Point - ->>> Point.x -1 ->>> p = Point() ->>> p -<__main__.Point instance at 0x2de918> ->>> p.x -1 -\end{verbatim} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\Large Basic Structure of a real class:} - -\begin{verbatim} -class Point(object): -# everything defined in here is in the class namespace - def __init__(self, x, y): - self.x = x - self.y = y -## create an instance of that class -p = Point(3,4) - -## access the attributes -print "p.x is:", p.x -print "p.y is:", p.y -\end{verbatim} - -{\large see: \verb|code/simple_class| } - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\LARGE The Initializer} - -\vfill -{\Large The \verb|__init__| special method is called when a new instance of a class is created.} - -\vfill -{\Large You can use it to do any set-up you need} - -\vfill -\begin{verbatim} -class Point(object): - def __init__(self, x, y): - self.x = x - self.y = y -\end{verbatim} -\vfill -{\Large It gets the arguments passed to the class constructor} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\LARGE \verb|self|} - -\vfill -{\Large The instance of the class is passed as the first parameter for every method.} - -\vfill -{\Large ``\verb|self|'' is only a convention -- but you DO want to use it.} - -\vfill -\begin{verbatim} -class Point(object): - def a_function(self, x, y): -... -\end{verbatim} -\vfill -{\Large Does this look familiar from C-style procedural programming?} -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -\begin{verbatim} -class Point(object): - def __init__(self, x, y): - self.x = x - self.y = y -\end{verbatim} - -\vfill -{\Large Anything assigned to a \verb|self.| attribute is kept in the instance -name space} - -\vfill -{\Large That's where all the instance-specific data is.} - -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -\begin{verbatim} -class Point(object): - size = 4 - color= "red" - def __init__(self, x, y): - self.x = x - self.y = y -\end{verbatim} - -\vfill -{\Large Anything assigned in the class scope is a class attribute -- every -instance of the class shares the same one.} -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -\begin{verbatim} -class Point(object): - size = 4 - color= "red" -... - def get_color(): - return self.color - ->>> p3.get_color() - 'red' -\end{verbatim} - -\vfill -{\Large class attributes are accessed with \verb|self| also..} -\vfill -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\Large Typical methods} -\begin{verbatim} -class Circle(object): - color = "red" - def __init__(self, diameter): - self.diameter = diameter - - def grow(self, factor=2): - self.diameter = self.diameter * factor -\end{verbatim} - -\vfill -{\Large methods take some parameters, manipulate the attributes in \verb|self|} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Classes} - -{\Large Gotcha!} -\begin{verbatim} -... - def grow(self, factor=2): - self.diameter = self.diameter * factor -... -In [205]: C = Circle(5) -In [206]: C.grow(2,3) - -TypeError: grow() takes at most 2 arguments (3 given) -\end{verbatim} - -\vfill -{\LARGE Huh???? I only gave 2} - -\vfill -{\Large (``self`` is implicitly passed in...)} -\end{frame} - - -%%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\Large Let's say you need to render some html...} - -\vfill -{\Large The goal is to build a set of classes that render an html page: -\verb|sample_html.html| -} - -\vfill -{\Large We'll start with a single class, then add some sub-classes to specialize the behavior} - -\vfill -More details in \verb|week-06/LAB_instuctions.rst(html)| -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\Large Step 1:} - -\begin{itemize} - \item Create an "Element" class for rendering an html element (xml element). - \item It should have class attributes for the tag name and the - indentation - \item the constructor signature should look like: - \verb|Element(content=None)| where content is a string - \item It should have an "append" method that can add another string to the content - \item It should have a \verb|render(file_out, ind = "")| method that renders the tag and the strings in the content. - - \verb|file_out| could be any file-like object. - - \verb|ind| is a string with enough spaces to indent properly. -\end{itemize} - -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\centering - -\vfill -{\LARGE Lightning Talks: } - -\vfill -{\Large Maria Petrova} - -\vfill -{\Large Patrick Thach} - - -\vfill -} -\end{frame} - -\section{Subclassing/Inheritance} - -% --------------------------------------------- -\begin{frame}[fragile]{Inheritance} - -In object-oriented programming (OOP), inheritance is a way to reuse code of -existing objects, or to establish a subtype from an existing object. - -\vfill -... - -\vfill -objects are defined by classes, classes can inherit attributes and behavior -from pre-existing classes called base classes, or super classes. - -\vfill -The resulting classes are known as derived classes or subclasses. - -\vfill -(\url{http://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29}) -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Subclassing} - -A subclass ``inherits'' all the attributes (methods, etc) of the parent class. - -\vfill -You can then change (``override'') some or all of the attributes to change the behavior. - -\vfill -The simplest subclass in Python: - -\begin{verbatim} -class A_Subclass(The_SuperClass): - pass -\end{verbatim} - -\vfill -\verb|A_subclass| now has exactly the same behavior as \verb|The_SuperClass| - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Overriding attributes} - -{\Large Overriding is as simple as creating a new attribute with the same name:} - -\vfill -\begin{verbatim} -class Circle(object): - color = "red" -... -class NewCircle(Circle): - color = "blue" ->>> nc = NewCircle ->>> print nc.color -blue -\end{verbatim} - -\vfill -all the \verb|self| instances will have the new attribute -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Overriding methods} - -{\Large Same thing, but with methods} - -\vfill -\begin{verbatim} -class Circle(object): -... - def grow(self, factor=2): - """grows the circle's diameter by factor""" - self.diameter = self.diameter * factor -... -class NewCircle(Circle): -... - def grow(self, factor=2): - """grows the area by factor...""" - self.diameter = self.diameter * math.sqrt(2) -\end{verbatim} -all the instances will have the new method -\end{frame} - -\begin{frame} - -{\Large -``Here's a program design suggestion: whenever you override a method, the -interface of the new method should be the same as the old. It should take -the same parameters, return the same type, and obey the same preconditions -and postconditions. If you obey this rule, you will find that any function -designed to work with an instance of a superclass, like a Deck, will also work -with instances of subclasses like a Hand or PokerHand. If you violate this -rule, your code will collapse like (sorry) a house of cards.'' -} -\vfill -\hfill ThinkPython 18.10 -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\Large Step 2:} - -\begin{itemize} - \item Create a couple subclasses of \verb|Element|, for a \verb|| tag - and \verb|

        | tag. Simply override the \verb|tag| class attribute. - \item Extend the \verb|Element.render()| method so that it can render other - elements inside the tag in addition to strings. Simple recursion should - do it. i.e. it can call the \verb|render()| method of the elements it - contains. - \item Deal with the content items that could be either simple strings or - \verb|Element|s with \verb|render| methods...there are a few ways to handle that... -\end{itemize} - -\end{frame} - - -%%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\Large Step 3:} - -\begin{itemize} - \item Create a \verb|| element -- simple subclass. - \item Create a \verb|OneLineTag| subclass of Element: - It should override the render method, to render everything on one line -- - for the simple tags, like: - - \verb| PythonClass - Class 6 example | - \item Create a Title subclass of \verb|OneLineTag| class for the title. - - \item You should now be able to render an html doc with a head element, with - a \verb|title| element in that, and a body element with some \verb|

        | - elements and some text. -\end{itemize} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Homework} - -{\LARGE Catch Up!} - -\vfill -{\Large Read up on OO if you haven't already} - -\vfill -{\Large Finish today's Lab} - -\vfill -{\Large Finish other Homework / Labs you may not have gotten to.} - -\vfill -{\Large Come up with a project proposal} - -\end{frame} - - -\end{document} - - diff --git a/slides_sources/old_versions/week-07/presentation-week-07.pdf b/slides_sources/old_versions/week-07/presentation-week-07.pdf deleted file mode 100644 index 0fe8f6bc..00000000 Binary files a/slides_sources/old_versions/week-07/presentation-week-07.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-07/presentation-week-07.tex b/slides_sources/old_versions/week-07/presentation-week-07.tex deleted file mode 100644 index 243de56d..00000000 --- a/slides_sources/old_versions/week-07/presentation-week-07.tex +++ /dev/null @@ -1,632 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Intro to Python: Week 1]{Introduction to Python\\ More OO -- Inheritance and Duck Typing \\ -Special methods} - -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{November 12, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning talks today:} - -\vfill -{\Large - -\vfill -Linh Tran - -\vfill -Maitri Kashyap - -\vfill -Sridharan Rajagopalan - -\vfill -Richard Smith -} -\vfill - -\end{frame} - - -\section{Review/Questions} - -% --------------------------------------------- -\begin{frame}{Review of Previous Class} - -{\LARGE -\begin{itemize} - \item lambda - \item Intro to OO - \item Start of HTML generation code -\end{itemize} -} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Homework review} - - \vfill - {\Large Questions? } - - \vfill - {\Large Overview of my html-generating classes so far...} - -\vfill -{\Large Demo of class vs. instance attributes} - -\end{frame} - - - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -\vfill -{\large Linh Tran} - -\vfill -{\large Maitri Kashyap} - -\end{frame} - - -%######################## -\section{More on Subclassing} - -% --------------------------------------------- -\begin{frame}[fragile]{Overriding \_\_init\_\_} - -{\Large \verb|__init__|common method to override} -\vfill -{\large You often need to call the super class \verb|__init__| as well} -\vfill -\begin{verbatim} -class Circle(object): - color = "red" - def __init__(self, diameter): - self.diameter = diameter -... -class CircleR(Circle): - def __init__(self, radius): - diameter = radius*2 - Circle.__init__(self, diameter) -\end{verbatim} -\vfill -exception to: "don't change the method signature" rule. -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{More subclassing} - -{\large You can also call the superclass' other methods:} -\vfill -\begin{verbatim} -class Circle(object): -... - def get_area(self, diameter): - return math.pi * (diameter/2.0)**2 - -class CircleR2(Circle): -... - def get_area(self): - return Circle.get_area(self, self.radius*2) -\end{verbatim} - -\vfill -There is nothing special about \verb|__init__| except that it gets called automatically. -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{When to Subclass} - -\vfill -{\Large ``Is a'' relationship: Subclass/inheritance} - -\vfill -{\Large ``Has a'' relationship: Composition} -\end{frame} - -\begin{frame}[fragile]{When to Subclass} - -{\Large ``Is a'' vs ``Has a'' } - -\vfill -You may have a class that needs to accumulate an arbitrary number of objects. - -\vfill -A list can do that -- so should you subclass list? - -\vfill -Ask yourself:\\ - -\vfill --- Is your class a list (with some extra functionality)?\\ -\hspace{0.4in}or\\ --- Does you class HAVE a list?\\ - -\vfill -You only want to subclass list if your class could be used anywhere a list can be used. -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Attribute resolution order} - -{\Large When you access an attribute: - -\vfill -\hspace{0.2in}\verb|An_Instance.something|} - -\vfill -{\Large Python looks for it in this order:} - -\vfill -\begin{enumerate} - \item Is it an instance attribute ? - \item Is it a class attribute ? - \item Is it a superclass attribute ? - \item Is it a super-superclass attribute ? - \item ... -\end{enumerate} - -\vfill -It can get more complicated...\\ -{\small -\url{http://www.python.org/getit/releases/2.3/mro/} \\ -\url{http://python-history.blogspot.com/2010/06/method-resolution-order.html} -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{What are Python classes, really?} - -{\Large Putting aside the OO theory...} - -\vfill -{\Large Python classes are:} - -\begin{itemize} - \item Namespaces - \begin{itemize} - \item One for the class object - \item One for each instance - \end{itemize} - \item Attribute resolution order - \item Auto tacking-on of \verb|self| -\end{itemize} - -\vfill -{\Large That's about it -- really!} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Type-Based dispatch} - -{\Large From Think Python:} - -\begin{verbatim} - if isinstance(other, A_Class): - Do_something_with_other - else: - Do_something_else -\end{verbatim} - -\vfill -{\Large Usually better to use ``duck typing'' (polymorphism)} - -\vfill -{\Large But when it's called for:} -\begin{itemize} - \item \verb|isinstance()| - \item \verb|issubclass()| -\end{itemize} - -\vfill -GvR: ``Five Minute Multi- methods in Python'':\\ -{\small \url{http://www.artima.com/weblogs/viewpost.jsp?thread=101605} } - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large We're going to do the rest: steps 4 - 8} - -{(Still using \verb|week-06/code/htmlrender|) } - -\vfill -{\Large Step 4:} - -\begin{itemize} - \item Extend the Element class to accept a set of attributes as keywords to the - constructor, i.e.: - \begin{verbatim} -Element("some text content", - id="TheList", - style="line-height:200\%") - \end{verbatim} - ( remember \verb|**kwargs| ? ) - \item The render method will need to be extended to render the attributes properly. -\end{itemize} - -\vfill -You can now render some \verb|

        | tags (and others) with attributes -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large Step 5:} - -\begin{itemize} - \item Create a \verb|SelfClosingTag| subclass of \verb|Element|, to render tags like: - - \verb|


        and
        | (horizontal rule and line break). - - \item You will need to override the render method to render just the one tag and - attributes. - - \item create a couple subclasses of SelfClosingTag for \verb|
        | - and \verb|
        | (Line break) or ??? if you like - \end{itemize} - -\vfill -You can now render an html page with a proper \verb|| (\verb|| and \verb|| elements) -\end{frame} - -\begin{frame}[fragile]{LAB} - -{\Large Step 6:} - -\begin{itemize} - \item Create an \verb|A| class for an anchor (link) element. Its constructor should - look like: \verb|A(self, link, content)| -- where link is the link, - and content is what you see. It can be called like so: - - \verb|A("http://google.com", "link")| - - \item You should be able to subclass from \verb|Element|, and only override - the \verb|__init__|\\ - -- Calling the \verb|Element __init__| from the \verb|A __init__| -\end{itemize} - -\vfill - You can now add a link to your web page. -\end{frame} - -\begin{frame}[fragile]{LAB} - -{\Large Step 7:} - -\begin{itemize} - \item Create \verb|Ul| class for an unordered list (really simple subclass of Element) - - \item Create \verb|Li| class for an element in a list (also really simple) - - \item add a list to your web page. - - \item Create a Header class -- this one should take an integer argument for the - header level. i.e \verb|<h1>, <h2>, <h3>|, called like: - - \item \verb|H(2, "The text of the header")| for an \verb|<h2>| header - - \item It can subclass from \verb|OneLineTag| -- overriding the \verb|__init__|, then calling - the superclass \verb|__init__| -\end{itemize} - -\end{frame} - -\begin{frame}[fragile]{LAB} - -{\Large Step 8:} - -\begin{itemize} - \item Update the Html element class to render the "\verb|<!DOCTYPE html>|" tag at the - head of the page, before the \verb|html| element. - - \item You can do this by subclassing \verb|Element|, overriding \verb|render()|, but then - calling \verb|Element.render()| from \verb|Html.render()|. - - \item Create a subclass of \verb|SelfClosingTag| for \verb|<meta charset="UTF-8" />| - and add the meta element to the beginning of the head element to give your document - an encoding. - - \item The doctype and encoding are HTML 5 and you can check this at: - \url{validator.w3.org.} - -\end{itemize} - -\vfill -You now have a pretty full-featured html renderer -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Review of HTML renderer lab} - -{\Large You have built an html generator, using:} - \begin{itemize} - \item A Base Class with a couple methods - \item Subclasses overriding class attributes - \item Subclasses overriding a method - \item Subclasses overriding the \verb|__init__| - \end{itemize} - -\vfill -{\Large These are the core OO approaches} - -\vfill -{\Large If you don't have it working, or don't think you ``get'' it:\\ - work on it for homework, and ask questions.} - -\end{frame} - - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -\vfill -{\large Sridharan Rajagopalan} - -\vfill -{\large Richard Smith} - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Multiple Inheritance} - -% --------------------------------------------- -\begin{frame}[fragile]{multiple inheritance} - -{\Large Multiple inheritance:\\ -\hspace{0.2in} Pulling from more than one class} - -\vfill -\begin{verbatim} -class Combined(Super1, Super2, Super3): - def __init__(self, something, something else): - Super1.__init__(self, ......) - Super2.__init__(self, ......) - Super3.__init__(self, ......) -\end{verbatim} -(calls to the super class \verb|__init__| are optional -- case dependent) - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{multiple inheritance} - -\vfill -{\Large Attribute resolution -- left to right} - -\begin{enumerate} - \item Is it an instance attribute ? - \item Is it a class attribute ? - \item Is it a superclass attribute ? - \begin{enumerate} - \item is the it an attribute of the left-most superclass? - \item is the it an attribute of the next superclass? - \item .... - \end{enumerate} - \item Is it a super-superclass attribute ? - \item ...also left to right... -\end{enumerate} - -\vfill -\url{http://python-history.blogspot.com/2010/06/method-resolution-order.html} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Mix-ins} - -{\Large Why would you want to do this?} - -\vfill -{\Large Hierarchies are not always simple:} -\vfill -{\large -\begin{itemize} - \item Animal - \begin{itemize} - \item Mammal - \begin{itemize} - \item GiveBirth() - \end{itemize} - \item Bird - \begin{itemize} - \item LayEggs() - \end{itemize} - \end{itemize} -\end{itemize} -} - -\vfill -{\Large Where do you put a Platypus or an Armadillo?} - -\vfill -{\Large Real World Example: \verb|FloatCanvas|} -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{New Style classes} - -{\Large You will see reference to ``new style'' classes} - -\vfill -{\Large These derive from \verb|object|} - -\vfill -{\Large Introduced in python2.2 to better merge types and classes, and clean up a few things} - -\vfill -{\Large Differences in method resolution order and properties} - -\vfill -{\Large Mostly the same, often makes no difference} - -\vfill -{\Large My advice: always subclass from \verb|object|} - -\end{frame} - -%----------------------------------- -\begin{frame}[fragile]{super} - -{\Large \verb|super(): |use it to call a superclass method, rather than exlicitly calling it:} - -\vfill -{\large instead of:} -\begin{verbatim} -class A(B): - def __init__(self, *args, **kwargs) - B.__init__(self, *argw, **kwargs) - ... -\end{verbatim} - -{\large You can do:} -\begin{verbatim} -class A(B): - def __init__(self, *args, **kwargs) - super(A, self).__init__(self, *argw, **kwargs) - ... -\end{verbatim} - -\vfill -{\Large There are some subtle differences with multiple inheritance} - -\end{frame} - -%-------------------------- -\begin{frame}[fragile]{super} - -{\Large Two seminal articles about \verb|super()|:} - -\vfill -{\LARGE ``Super Considered Harmful''}\\[0.1in] -{\Large \hspace{0.5in}-- James Knight } - -\vfill -\url{https://fuhm.net/super-harmful/} - -\vfill -{\LARGE ``super() considered super!''}\\[0.1in] -{\Large \hspace{0.5in}-- Raymond Hettinger } - -\vfill -\url{http://rhettinger.wordpress.com/2011/05/26/super-considered-super/} -\vfill - -{\large (Both worth reading....)} -\end{frame} - - - - -%------------------------------- -\begin{frame}[fragile]{Wrap Up} - -{\LARGE Thinking OO in Python:} - -\vfill -{\large Think about what makes sense for your code:} -\begin{itemize} - \item {\large Code re-use} - \item {\large Clean APIs} - \item {\large ... } -\end{itemize} - -\vfill -{\large Don't be a slave to what OO is \emph{supposed} to look like. } - -\vfill -{\large Let OO work for you, not \emph{create} work for you} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{Wrap Up} - -{\Large OO in Python:} - -\vfill -{\Large The Art of Subclassing}: Raymond Hettinger - -\vfill -{\small \url{http://pyvideo.org/video/879/the-art-of-subclassing}} - -\vfill -''classes are for code re-use -- not creating taxonomies'' - -\vfill -{\Large Stop Writing Classes}: Jack Diederich - -\vfill -{\small \url{http://pyvideo.org/video/880/stop-writing-classes}} - -\vfill -``If your class has only two methods -- and one of them is \verb|__init__| --- you don't need a class '' -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Homework} - -{\Large Finish the labs.} - -\vfill -{\Large Watch the videos.} - -\vfill -{\Large Readup more on OO design.} - - -\vfill -{\LARGE Your Project:} -\begin{itemize} - \item By next week, send me a project proposal: can be short and sweet. - \item Think about how you might use OO: - \begin{itemize} - \item What classes naturally fall out of the problem? - \item NOTE: maybe none! - \end{itemize} -\end{itemize} - -\end{frame} - - -\end{document} - - diff --git a/slides_sources/old_versions/week-08.5/Readme.rst b/slides_sources/old_versions/week-08.5/Readme.rst deleted file mode 100644 index db72b5fb..00000000 --- a/slides_sources/old_versions/week-08.5/Readme.rst +++ /dev/null @@ -1,104 +0,0 @@ -GUI progamming / wxPython -########################### - -Optional class for the Intro to Python course, covering GUI programming, in particular the wxPython toolkit. - -Introduction -============== - -There a number of toolkits for doing Graphical User Interface (GUI) development with Python -- they each have their own advantages and disadvantages, so it can be a bit hard to know what to select. IN this class, we will be covering wxPython -- honestly, the reason for hat is that I am most familiar with that toolkit, rather than it being an endorsement for that toolkit for any particular other project. I had good reasons for selecting wxPython years ago, but some of those reasons may not apply to your projects, and may not even be relevant anymore. - -Nevertheless, all desktop GUI toolkits have a fair bit on common: Windows, Frames and Controls, A layout mechanism, and the core concept of event-driven development. So learning one will help you to learn others in the future if need be. - - -Installing wxPython -===================== - -wxPython is a wrapper around the wxWidgets toolkit, written on C++. wxWidget itself is a wrapper around various platform specific GUI APIs, and is a fairly complete frame work including some font handling, image manipulation, etc. As a result it is a significant challenge to build. I highly suggest you use pre-build binaries: - -NOTE: when you install wxPython, be sure to also get the "Docs and Demos" -- usually a separate download -- the wxPython Demo, in particular is a treasure trove of examples. - - -Windows ----------- - -Binaries for wxPython on Windows can be found on the wxPython web site. I suggest the "development" version -- it is called "unstable", but that means the API is unstable, not the actual code. Version 2.9.5 is the latest as of this writing. MAke sure to get the version for python2.7 and either 32 or 64 bits, depending on which version of Python you have. It should work with the python from python.org. - -(note that the link on the left sidebar of the site takes you to the top of downloads page, so you'll need to scroll down to find the development builds) - -If you have python from Enthought, use the wxPython that they provide. If you have Anoconda, I don't think they have wxPython -- it's possible that the one from wxpython.org will world with it with some tweaking, or you will need to install the python.org python. - -OS-X -------- - -Binaries for wxPython on OS-X can be found on the wxPython web site. I suggest the "development" version -- it is called "unstable", but that means the API is unstable, not the actual code. Version 2.9.5 is the latest as of this writing. Make sure to get the version for python2.7 Cocoa version: wxPython2.9-osx-cocoa-py2.7. This will work with the 32+64 bit Intel python binaries available from python.org. - -(note that the link on the left sidebar of the site takes you to the top of downloads page, so you'll need to scroll down to find the development builds) - -If you have python from Enthought (Canopy), use the wxPython that they provide. If you have Anaconda, I don't think they have wxPython -- you will need to install the python.org python and use that. - -Linux --------- - -Hopefully, your distribution provides builds of wxPython: - -apt-get install wxpython (or similar) - -Use whatever version your distro provides, at thin point in the game there is no need to deal with building to get a newer version. - -If your distro doesn't have it, then you are stuck with building yourself -- see the wxpython.org site for instructions. - -Documentation and Examples: -============================= - -There are many sources of documentation and examples. Start with the wxpython.org web site, but here are a few other pointers: - - -Learning wxPython -------------------- - -This page is a good place to start: - -http://wiki.wxpython.org/How%20to%20Learn%20wxPython - -It has a lot of good hints for getting started. - -The Demo ----------- - -Usually a separate install, but the wxPython Demo app is really really useful -- make sure to install it and check it out. It has a small demo of virtually all the features of wxPython -- this lets you not only see how to use different widgets, etc, but also lets you see what they look like and how they work -- great if you're really not sure what a "Choice control", for instance, actually is... - -The Wiki ---------- - -The wxpython wiki: http://wiki.wxpython.org/ has a lot of good stuff in it. Some is a bit outdated, but well worth a look in any case. - -Blogs --------- - -There is good stuff in various blogs, etc. Google will help you find things. But Mike Driscol's Blog is particularly good -- he's been an active member of the wxPyton community for years, and loves to write up simple demonstrations ans explanations: - -http://www.blog.pythonlibrary.org/ - -My Demo Collection --------------------- - -Over the years, I've built up a substantial collection of small wxPthon demos. Most of them are tiny stand-alone apps that test or demonstrate individual features of teh toolkit. you can find it on gitHub here: - -https://github.com/PythonCHB/wxPythonDemos - - - - - - - - - - - - - - - - diff --git a/slides_sources/old_versions/week-08.5/code/CalculatorDemo.py b/slides_sources/old_versions/week-08.5/code/CalculatorDemo.py deleted file mode 100755 index 424d537e..00000000 --- a/slides_sources/old_versions/week-08.5/code/CalculatorDemo.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python - -""" -wxPython Calculator Demo in 50 lines of code - -This demo was pulled from the wxPython Wiki: - -http://wiki.wxpython.org/CalculatorDemo -by Miki Tebeka - -It has been altered to allow it to be "driven" by an external script, -plus a little layout improvement -""" - - -# Calculator GUI: - -# ___________v -# [7][8][9][/] -# [4][5][6][*] -# [1][2][3][-] -# [0][.][C][+] -# [ = ] - -from __future__ import division # So that 8/3 will be 2.6666 and not 2 - -import wx - -class Calculator(wx.Panel): - '''Main calculator dialog''' - def __init__(self, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - sizer = wx.BoxSizer(wx.VERTICAL) # Main vertical sizer - - self.display = wx.ComboBox(self) # Current calculation - sizer.Add(self.display, 0, wx.EXPAND|wx.BOTTOM, 8) # Add to main sizer - - # [7][8][9][/] - # [4][5][6][*] - # [1][2][3][-] - # [0][.][C][+] - gsizer = wx.GridSizer(4, 4, 8, 8) - for row in (("7", "8", "9", "/"), - ("4", "5", "6", "*"), - ("1", "2", "3", "-"), - ("0", ".", "C", "+")): - for label in row: - b = wx.Button(self, label=label, size=(40,-1)) - gsizer.Add(b) - b.Bind(wx.EVT_BUTTON, self.OnButton) - sizer.Add(gsizer, 1, wx.EXPAND) - - # [ = ] - b = wx.Button(self, label="=") - b.Bind(wx.EVT_BUTTON, self.OnButton) - sizer.Add(b, 0, wx.EXPAND|wx.ALL, 8) - self.equal = b - - # Set sizer and center - self.SetSizerAndFit(sizer) - - def OnButton(self, evt): - '''Handle button click event''' - - # Get title of clicked button - label = evt.GetEventObject().GetLabel() - - if label == "=": # Calculate - self.Calculate() - elif label == "C": # Clear - self.display.SetValue("") - - else: # Just add button text to current calculation - self.display.SetValue(self.display.GetValue() + label) - self.display.SetInsertionPointEnd() - self.equal.SetFocus() # Set the [=] button in focus - - def Calculate(self): - """ - do the calculation itself - - in a separate method, so it can be called outside of a button event handler - """ - try: - compute = self.display.GetValue() - # Ignore empty calculation - if not compute.strip(): - return - - # Calculate result - result = eval(compute) - - # Add to history - self.display.Insert(compute, 0) - - # Show result - self.display.SetValue(str(result)) - except Exception, e: - wx.LogError(str(e)) - return - - def ComputeExpression(self, expression): - """ - Compute the expression passed in. - - This can be called from another class, module, etc. - """ - print "ComputeExpression called with:", expression - self.display.SetValue(expression) - self.Calculate() - -class MainFrame(wx.Frame): - def __init__(self, *args, **kwargs): - kwargs.setdefault('title', "Calculator") - wx.Frame.__init__(self, *args, **kwargs) - - self.calcPanel = Calculator(self) - - # put the panel on -- in a sizer to give it some space - S = wx.BoxSizer(wx.VERTICAL) - S.Add(self.calcPanel, 1, wx.GROW|wx.ALL, 10) - self.SetSizerAndFit(S) - self.CenterOnScreen() - - -if __name__ == "__main__": - # Run the application - app = wx.App(False) - frame = MainFrame(None) - frame.Show() - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/address_book/a_book.json b/slides_sources/old_versions/week-08.5/code/address_book/a_book.json deleted file mode 100644 index f9539048..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book/a_book.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "phone": "123-456-8888", - "first_name": "Chris", - "last_name": "Barker", - "email": "PythonCHB@gmail.com" - }, - { - "phone": "510-555-1234", - "first_name": "Fred", - "last_name": "Jones", - "email": "FredJones@some_company.com" - }, - { - "phone": "423-321-9876", - "first_name": "Nancy", - "last_name": "Wilson", - "email": "Wilson.Nancy@gmail.com" - }, - { - "phone": "555-555-5555", - "first_name": "Charles", - "last_name": "Dickens", - "email": "chuck@victorian.england.com" - } -] \ No newline at end of file diff --git a/slides_sources/old_versions/week-08.5/code/address_book/address_book_app.py b/slides_sources/old_versions/week-08.5/code/address_book/address_book_app.py deleted file mode 100755 index 4472d660..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book/address_book_app.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env python - -""" -Example of a very basic, minimal wxPython address book application - -This module defines the main Frame - -""" - -import os - -import wx -from address_book_data import AddressBook -from entry_form import AddBookForm -from switcher import Switcher - -class AddBookFrame(wx.Frame): - def __init__(self, add_book, *args, **kwargs): - """ - initilizer for the main from for the AddressBook app. - - :param add_book: the address book class to manipulate - :type add_book: A address_book_data.AddressBook instance - - """ - - kwargs.setdefault('title', "Micro Address Book") - wx.Frame.__init__(self, *args, **kwargs) - - self.add_book = add_book - self.current_index = 0 - - # creae a status bar for messages... - self.CreateStatusBar() - - # create the entryPanel - self.entryPanel = AddBookForm(add_book.book[self.current_index], self) - - # put them in a Sizer to lay out - S = wx.BoxSizer(wx.VERTICAL) - S.Add(wx.StaticLine(self,style=wx.LI_HORIZONTAL), 0, wx.EXPAND) - S.Add(self.entryPanel, 0, wx.ALL|wx.EXPAND, 4) - S.Add((1,5)) - S.Add(wx.StaticLine(self,style=wx.LI_HORIZONTAL), 0, wx.EXPAND) - - self.SetSizerAndFit(S) - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - - closeMenuItem = fileMenu.Append(wx.ID_EXIT, "&Close", "Close the file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - def next(self): - """ - move to the next record in the address book - """ - try: - self.entryPanel.entry = self.add_book.book[self.current_index+1] - self.current_index+=1 - except IndexError: - print "At end of records...." - - def previous(self): - """ - move to the next record in the address book - """ - if self.current_index > 0: - self.current_index-=1 - self.entryPanel.entry = self.add_book.book[self.current_index] - - def onNewRecord(self, evt=None): - index = self.add_book.new_record() - self.entryPanel.entry = self.add_book.book[index] - - def onOpen(self, evt=None): - """This method opens an existing file""" - dlg = wx.FileDialog( - self, message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard="*.json", - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.add_book.load_from_file(filename=path) - else : - print "The file dialog was canceled" - dlg.Destroy() - - - def onClose(self, evt=None): - print "close menu selected" - self.add_book.close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - -class AddBookApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - a_book = AddressBook() - a_book.load_from_file() - - f = AddBookFrame(a_book, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - - app = AddBookApp(False) - - - - ## set up the WIT -- to help debug sizers - import wx.lib.inspection - wx.lib.inspection.InspectionTool().Show() - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/address_book/address_book_data.py b/slides_sources/old_versions/week-08.5/code/address_book/address_book_data.py deleted file mode 100755 index d610787d..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book/address_book_data.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python - -""" -application logic code for ultra simple -address book app... -""" - -import json - -class AddressBook(object): - """ - very simple data model -- just a list of dicts - - each dict represents an entry in the address book - """ - fields = [ "phone", - "first_name", - "last_name", - "email", - ] - - def __init__(self, filename="a_book.json"): - self.filename = filename - self.book = [] - self.new_record() - - def new_record(self): - """ - and a new, empty record - - :returns index: index of the new, empty record - """ - self.book.append(dict.fromkeys(self.fields, "")) - return len(self.book) - 1 - - def save_to_file(self, filename=None): - if filename is not None : - self.filename = filename - json.dump(self.book, open(self.filename, 'wb'), indent=4 ) - - def load_from_file(self, filename=None): - if filename is not None : - self.filename = filename - self.book = json.load( open(self.filename, 'rb') ) - - def close(self): - """ - clear out the data... - leave it with one empty dict - """ - del self.book[:] - self.book.append({}) - -if __name__ == "__main__": - import pprint - a_book = AddressBook() - a_book.load_from_file() - - print "the data in the address book is:" - pprint.pprint(a_book.book) - - print - print "the first entry is:" - entry = a_book.book[0] - print entry - print "the first entry's name is:" - print entry['first_name'], entry['last_name'] - - - diff --git a/slides_sources/old_versions/week-08.5/code/address_book/entry_form.py b/slides_sources/old_versions/week-08.5/code/address_book/entry_form.py deleted file mode 100755 index 46f2e6c0..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book/entry_form.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python - -""" -The basic form for the address book - -This is the GUI for editing a single record. - -""" - -import wx - -class AddBookForm(wx.Panel): - def __init__(self, a_entry, *args, **kwargs): - """ - create a new AddBookForm - - :param a_entry: a dict for the address book entry - """ - wx.Panel.__init__(self, *args, **kwargs) - - self._entry = a_entry - - ## create text boxes to edit: first name, last name, phone, email. - self.fname_text = wx.TextCtrl(self) - self.lname_text = wx.TextCtrl(self) - ## still need phone and email here... - - ## use a FlexGridSizer: - S = wx.FlexGridSizer(rows=0, cols=2, vgap=8, hgap=8) - S.AddGrowableCol(idx=1, proportion=1) - - S.Add(wx.StaticText(self, label="First Name:"), 0, - wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - S.Add(self.fname_text, flag=wx.EXPAND) - - S.Add(wx.StaticText(self, label="Last Name:"), 0, - wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - S.Add(self.lname_text, flag=wx.EXPAND) - - # Save and Cancel buttons - sav_but = wx.Button(self, label="Save Record") - sav_but.Bind(wx.EVT_BUTTON, self.onSave) - can_but = wx.Button(self, label="Reset Record") - can_but.Bind(wx.EVT_BUTTON, self.onCancel) - - # a sizer for the buttons: - but_sizer = wx.BoxSizer(wx.HORIZONTAL) - but_sizer.Add((1,1), 1) #stretchable spave to shift buttons right - but_sizer.Add(can_but, 0, wx.ALL, 4) - but_sizer.Add(sav_but, 0, wx.ALL, 4) - - #Put the whole thing in another sizer to - # layout the buttons... - Outer_Sizer = wx.BoxSizer(wx.VERTICAL) - Outer_Sizer.Add(S, 0, wx.ALL|wx.EXPAND, 10) - Outer_Sizer.Add(but_sizer, 0, wx.EXPAND|wx.RIGHT, 10) - self.SetSizerAndFit(Outer_Sizer) - - self.load_data() - - def onSave(self, evt=None): - # save the data in the form - self.save_data() - - def onCancel(self, evt=None): - # restore the form - self.load_data() - - ### propery for changing the active record - def _get_entry(self, entry): - return self._entry - - def _set_entry(self, entry): - self._entry = entry - self.load_data() - entry = property(_get_entry, _set_entry, doc="dict of record to be edited") - - def load_data(self): - """ - load the data into the form from the data dict - """ - data = self._entry - self.fname_text.Value = data.setdefault( u'first_name', "" ) - self.lname_text.Value = data.setdefault( u'last_name', "" ) - - def save_data(self): - """ - save the data from the form to the data dict - """ - data = self._entry - data[u'first_name'] = self.fname_text.Value - data[u'last_name'] = self.lname_text.Value - - -# I like to have a little test app so it can be run on its own -if __name__ == "__main__": - - # a sample entry: - entry = {u'email': u'PythonCHB@gmail.com', - u'first_name': u'Chris', - u'last_name': u'Barker', - u'phone': u'123-456-7890'} - - app = wx.App(False) - f = wx.Frame(None) - p = AddBookForm(entry, f) - f.Show() - app.MainLoop() \ No newline at end of file diff --git a/slides_sources/old_versions/week-08.5/code/address_book/switcher.py b/slides_sources/old_versions/week-08.5/code/address_book/switcher.py deleted file mode 100755 index 81eb7d6c..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book/switcher.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python - -""" -A custom widget to switch between different entries in the address book - -Subclassed from a wx.Panel -""" - -import wx - -class Switcher(wx.Panel): - def __init__(self, parent, *args, **kwargs): - """ - create a new switcher instance. - - :param parent: the parent frame -- this is designed to go on an - AddBookFrame object - - - :params *args, **kwargs: all the other arguments that a wx.Window takes. - """ - wx.Panel.__init__(self, parent, *args, **kwargs) - - self.add_book_frame = parent - - ## add some widgets here to do the switching - - - def onPrev(self, evt=None): - # save the data in the form - print "in onPrev" - self.add_book_frame.previous() - def onNext(self, evt=None): - # restore the form - print "in onNext" - self.add_book_frame.next() - -class TestFrame(wx.Frame): - """ - simple Frame with jsut enough to text the Switcher - """ - def next(self): - print "next() called in frame" - def previous(self): - print "previous() called in frame" - -# I like to have a little test app so it can be run on its own -if __name__ == "__main__": - - app = wx.App(False) - f = TestFrame(None) - p = Switcher(f) - f.Show() - app.MainLoop() - - diff --git a/slides_sources/old_versions/week-08.5/code/address_book_solution/.DS_Store b/slides_sources/old_versions/week-08.5/code/address_book_solution/.DS_Store deleted file mode 100644 index 5008ddfc..00000000 Binary files a/slides_sources/old_versions/week-08.5/code/address_book_solution/.DS_Store and /dev/null differ diff --git a/slides_sources/old_versions/week-08.5/code/address_book_solution/a_book.json b/slides_sources/old_versions/week-08.5/code/address_book_solution/a_book.json deleted file mode 100644 index f9539048..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book_solution/a_book.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "phone": "123-456-8888", - "first_name": "Chris", - "last_name": "Barker", - "email": "PythonCHB@gmail.com" - }, - { - "phone": "510-555-1234", - "first_name": "Fred", - "last_name": "Jones", - "email": "FredJones@some_company.com" - }, - { - "phone": "423-321-9876", - "first_name": "Nancy", - "last_name": "Wilson", - "email": "Wilson.Nancy@gmail.com" - }, - { - "phone": "555-555-5555", - "first_name": "Charles", - "last_name": "Dickens", - "email": "chuck@victorian.england.com" - } -] \ No newline at end of file diff --git a/slides_sources/old_versions/week-08.5/code/address_book_solution/address_book_app.py b/slides_sources/old_versions/week-08.5/code/address_book_solution/address_book_app.py deleted file mode 100755 index 7758cd3c..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book_solution/address_book_app.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal wxPython address book application - -This module defines the main Frame -""" - -import os - -import wx -from address_book_data import AddressBook -from entry_form import AddBookForm -from switcher import Switcher - -class AddBookFrame(wx.Frame): - def __init__(self, add_book, *args, **kwargs): - """ - initilizer for the main from for the AddressBook app. - - :param add_book: the address book class to manipulate - :type add_book: A address_book_data.AddressBook instance - - """ - - kwargs.setdefault('title', "Micro Address Book") - wx.Frame.__init__(self, *args, **kwargs) - - self.add_book = add_book - self.current_index = 0 - - # creae a status bar for messages... - self.CreateStatusBar() - - # create the switcher - self.switcher = Switcher(self) - - # create the entryPanel - self.entryPanel = AddBookForm(add_book.book[self.current_index], self) - - # A new record button: - new_record_but = wx.Button(self, label="New Record") - new_record_but.Bind(wx.EVT_BUTTON, self.onNewRecord) - - # put them in a Sizer to lay out - S = wx.BoxSizer(wx.VERTICAL) - S.Add(self.switcher, 0, wx.ALL|wx.ALIGN_CENTER, 4) - S.Add(wx.StaticLine(self,style=wx.LI_HORIZONTAL), 0, wx.EXPAND) - S.Add(self.entryPanel, 0, wx.ALL|wx.EXPAND, 4) - S.Add((1,5)) - S.Add(wx.StaticLine(self,style=wx.LI_HORIZONTAL), 0, wx.EXPAND) - S.Add(new_record_but, 0, wx.ALL|wx.ALIGN_RIGHT, 4) - - self.SetSizerAndFit(S) - self.switcher.Fit() - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - openMenuItem = fileMenu.Append(wx.ID_OPEN, "&Open", "Open a file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_EXIT, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - saveMenuItem = fileMenu.Append(wx.ID_SAVE, "&Save", "Save the file" ) - self.Bind(wx.EVT_MENU, self.onSave, saveMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - def next(self): - """ - move to the next record in the address book - """ - try: - self.entryPanel.entry = self.add_book.book[self.current_index+1] - self.current_index+=1 - except IndexError: - print "At end of records...." - def previous(self): - """ - move to the next record in the address book - """ - if self.current_index > 0: - self.current_index-=1 - self.entryPanel.entry = self.add_book.book[self.current_index] - - def onNewRecord(self, evt=None): - index = self.add_book.new_record() - self.entryPanel.entry = self.add_book.book[index] - - def onOpen(self, evt=None): - """This method opens an existing file""" - dlg = wx.FileDialog( - self, message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard="*.json", - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.add_book.load_from_file(filename=path) - else : - print "The file dialog was canceled" - dlg.Destroy() - - def onSave(self, evt=None): - print "in onSave" - self.SetStatusText("Saving: %s"%self.add_book.filename) - self.add_book.save_to_file() - - def onClose(self, evt=None): - print "close menu selected" - self.add_book.close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - -class AddBookApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - a_book = AddressBook() - a_book.load_from_file() - - f = AddBookFrame(a_book, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - - app = AddBookApp(False) - - - - ## set up the WIT -- to help debug sizers - import wx.lib.inspection - wx.lib.inspection.InspectionTool().Show() - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/address_book_solution/address_book_data.py b/slides_sources/old_versions/week-08.5/code/address_book_solution/address_book_data.py deleted file mode 100755 index d610787d..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book_solution/address_book_data.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python - -""" -application logic code for ultra simple -address book app... -""" - -import json - -class AddressBook(object): - """ - very simple data model -- just a list of dicts - - each dict represents an entry in the address book - """ - fields = [ "phone", - "first_name", - "last_name", - "email", - ] - - def __init__(self, filename="a_book.json"): - self.filename = filename - self.book = [] - self.new_record() - - def new_record(self): - """ - and a new, empty record - - :returns index: index of the new, empty record - """ - self.book.append(dict.fromkeys(self.fields, "")) - return len(self.book) - 1 - - def save_to_file(self, filename=None): - if filename is not None : - self.filename = filename - json.dump(self.book, open(self.filename, 'wb'), indent=4 ) - - def load_from_file(self, filename=None): - if filename is not None : - self.filename = filename - self.book = json.load( open(self.filename, 'rb') ) - - def close(self): - """ - clear out the data... - leave it with one empty dict - """ - del self.book[:] - self.book.append({}) - -if __name__ == "__main__": - import pprint - a_book = AddressBook() - a_book.load_from_file() - - print "the data in the address book is:" - pprint.pprint(a_book.book) - - print - print "the first entry is:" - entry = a_book.book[0] - print entry - print "the first entry's name is:" - print entry['first_name'], entry['last_name'] - - - diff --git a/slides_sources/old_versions/week-08.5/code/address_book_solution/entry_form.py b/slides_sources/old_versions/week-08.5/code/address_book_solution/entry_form.py deleted file mode 100755 index 7c3d14ee..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book_solution/entry_form.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python - -""" -The basic formm for the address book - -This gets a Panel to itself -""" - -import wx - -class AddBookForm(wx.Panel): - def __init__(self, a_entry, *args, **kwargs): - """ - create a new AddBookForm - - :param a_entry: a dict for the address book entry - """ - wx.Panel.__init__(self, *args, **kwargs) - - self._entry = a_entry - - ## create text boxes to edit: first name, last name, phone, email. - self.fname_text = wx.TextCtrl(self) - self.lname_text = wx.TextCtrl(self) - self.phone_text = wx.TextCtrl(self) - self.email_text = wx.TextCtrl(self) - - ## use a FlexGridSizer: - S = wx.FlexGridSizer(rows=0, cols=2, vgap=8, hgap=8) - S.AddGrowableCol(idx=1, proportion=1) - - S.Add(wx.StaticText(self, label="First Name:"), 0, - wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - S.Add(self.fname_text, flag=wx.EXPAND) - - S.Add(wx.StaticText(self, label="Last Name:"), 0, - wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - S.Add(self.lname_text, flag=wx.EXPAND) - - S.Add(wx.StaticText(self, label="Phone Number:"), 0, - wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - S.Add(self.phone_text, flag=wx.EXPAND) - - S.Add(wx.StaticText(self, label="Email Address:"), 0, - wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) - S.Add(self.email_text, flag=wx.EXPAND) - - # Save and Cancel buttons - sav_but = wx.Button(self, label="Save Record") - sav_but.Bind(wx.EVT_BUTTON, self.onSave) - can_but = wx.Button(self, label="Reset Record") - can_but.Bind(wx.EVT_BUTTON, self.onCancel) - - # a sizer for the buttons: - but_sizer = wx.BoxSizer(wx.HORIZONTAL) - but_sizer.Add((1,1), 1) #stretchable spave to shift buttons right - but_sizer.Add(can_but, 0, wx.ALL, 4) - but_sizer.Add(sav_but, 0, wx.ALL, 4) - - #Put the whole thing in another sizer to - # layout the buttons... - Outer_Sizer = wx.BoxSizer(wx.VERTICAL) - Outer_Sizer.Add(S, 0, wx.ALL|wx.EXPAND, 10) - Outer_Sizer.Add(but_sizer, 0, wx.EXPAND|wx.RIGHT, 10) - self.SetSizerAndFit(Outer_Sizer) - - self.load_data() - - def onSave(self, evt=None): - # save the data in the form - self.save_data() - - def onCancel(self, evt=None): - # restore the form - self.load_data() - - def _get_entry(self, entry): - return self._entry - - def _set_entry(self, entry): - self._entry = entry - self.load_data() - - entry = property(_get_entry, _set_entry) - - def load_data(self): - """ - load the data into the form from the data dict - """ - data = self._entry - self.fname_text.Value = data.setdefault( u'first_name', "" ) - self.lname_text.Value = data.setdefault( u'last_name', "" ) - self.phone_text.Value = data.setdefault( u'phone', "" ) - self.email_text.Value = data.setdefault( u'email', "" ) - - def save_data(self): - """ - save the data from the form from the data dict - """ - data = self._entry - data[u'first_name'] = self.fname_text.Value - data[u'last_name'] = self.lname_text.Value - data[u'phone'] = self.phone_text.Value - data[u'email'] = self.email_text.Value - - -# I like to have a little test app so it can be run on its own -if __name__ == "__main__": - - # a sample entry: - entry = {u'email': u'PythonCHB@gmail.com', - u'first_name': u'Chris', - u'last_name': u'Barker', - u'phone': u'123-456-7890'} - - app = wx.App(False) - f = wx.Frame(None) - p = AddBookForm(entry, f) - f.Show() - app.MainLoop() \ No newline at end of file diff --git a/slides_sources/old_versions/week-08.5/code/address_book_solution/switcher.py b/slides_sources/old_versions/week-08.5/code/address_book_solution/switcher.py deleted file mode 100755 index b61239dd..00000000 --- a/slides_sources/old_versions/week-08.5/code/address_book_solution/switcher.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python - -""" -A custom widget to switch between different entries in the address book - -Subclassed from a wx.Panel -""" - -import wx - -class Switcher(wx.Panel): - def __init__(self, parent, *args, **kwargs): - """ - create a new swither instance. - - :param parent: the parent frame -- this is designed to go on an - AddBookFrame object - - - :params *args, **kwargs: all the other arguments that a wx.Window takes. - """ - print "in __init__" - wx.Panel.__init__(self, parent, *args, **kwargs) - - self.add_book_frame = parent - - ##Create the buttons to scroll through add_book_frame - prev_button = wx.Button(self, label="Previous") - prev_button.Bind(wx.EVT_BUTTON, self.onPrev) - - next_button = wx.Button(self, label="Next") - next_button.Bind(wx.EVT_BUTTON, self.onNext) - - ## use a Sizer to lay it out - S = wx.BoxSizer(wx.HORIZONTAL) - - S.Add(prev_button, 1, wx.ALL, 4) - S.Add((10,1),0) - S.Add(wx.StaticText(self,label="AddressBook"), - 0, - wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, - 4) - S.Add((10,1),0) - S.Add(next_button, 1,wx.ALL, 4) - - self.SetSizerAndFit(S) - - def onPrev(self, evt=None): - # save the data in the form - print "in onPrev" - self.add_book_frame.previous() - def onNext(self, evt=None): - # restore the form - print "in onNext" - self.add_book_frame.next() -class TestFrame(wx.Frame): - """ - simple Frame with jsut enough to text the Switcher - """ - def next(self): - print "next() called in frame" - def previous(self): - print "previous() called in frame" - -# I like to have a little test app so it can be run on its own -if __name__ == "__main__": - - app = wx.App(False) - f = TestFrame(None) - p = Switcher(f) - f.Show() - app.MainLoop() - - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_1.py b/slides_sources/old_versions/week-08.5/code/basic_app_1.py deleted file mode 100755 index 872414a6..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_1.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application. -""" - -import wx - -class TestFrame(wx.Frame): - def __init__(self, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do in this case - """ - f = TestFrame(None) - f.Show() - - return True - -if __name__ == "__main__": - app = TestApp(False) - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_2.py b/slides_sources/old_versions/week-08.5/code/basic_app_2.py deleted file mode 100755 index 04b9f27a..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_2.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application - -This version adds a basic menu bar with a file menu -""" - -import wx - - -class AppLogic(object): - """ - A class to hold the application Application Logic. - - You generally don't want the real logic of the app mixed - in with the GUI - - In a real app, this would be a substantial collection of - modules, classes, etc... - """ - def file_open(self, filename="default_name"): - """This method opens a file""" - print "Open a file: " - print "I'd be opening file: %s now"%filename - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class TestFrame(wx.Frame): - def __init__(self, app_logic, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - self.app_logic = app_logic - - # Add a panel so it looks the correct on all platforms - self.panel = wx.Panel(self, wx.ID_ANY) - - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open a file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_ANY, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - def onOpen(self, evt=None): - print "open menu selected" - print evt - self.app_logic.file_open() - - def onClose(self, evt=None): - print "close menu selected" - self.app_logic.file_close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - app_logic = AppLogic() - f = TestFrame(app_logic, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - app = TestApp(False) - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_3.py b/slides_sources/old_versions/week-08.5/code/basic_app_3.py deleted file mode 100755 index 0f992eec..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_3.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application - -This version adds a basic menu bar with a file menu -""" - -import wx -import os - -#-------------------------------------------------------------- - -# This is how you pre-establish a file filter so that the dialog -# only shows the extension(s) you want it to. -wildcard = "Python source (*.py)|*.py|" \ - "Compiled Python (*.pyc)|*.pyc|" \ - "SPAM files (*.spam)|*.spam|" \ - "Egg file (*.egg)|*.egg|" \ - "All files (*.*)|*.*" - -#-------------------------------------------------------------- - -class AppLogic(object): - """ - A class to hold the Application Logic. - - You generally don't want the real logic of the app mixed - in with the GUI - - In a real app, this would be a substantial collection of - modules, classes, etc... - """ - - def file_open(self, filename="default_name"): - """This method opens a file""" - print "Open a file: " - print "I'd be opening file: %s now"%filename - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class TestFrame(wx.Frame): - def __init__(self, app_logic, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - self.app_logic = app_logic - - # Add a panel so it looks correct on all platforms - self.panel = wx.Panel(self, wx.ID_ANY) - - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - - saveasMenuItem = fileMenu.Append(wx.ID_ANY, "&Save As", "Create a new file") - self.Bind(wx.EVT_MENU, self.onSaveAs, saveasMenuItem ) - - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open an existing file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_ANY, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - - def onClose(self, evt=None): - print "close menu selected" - self.file_close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - def onSaveAs ( self, evt=None ): - """This method saves the file with a new name""" - - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'save' dialog. - # - # Unlike the 'open dialog' example found elsewhere, this example does NOT - # force the current working directory to change if the user chooses a different - # directory than the one initially set. - dlg = wx.FileDialog(self, - message="Save file as ...", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.SAVE ) - - # This sets the default filter that the user will initially see. Otherwise, - # the first filter in the list will be used by default. - dlg.SetFilterIndex(2) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - print "In onSaveAs, the path is %s" % path - # Normally, at this point you would save your data using the file and path - # data that the user provided to you, but since we didn't actually start - # with any data to work with, that would be difficult. - # - # The code to do so would be similar to this, assuming 'data' contains - # the data you want to save: - # - # fp = file(path, 'w') # Create file anew - # fp.write(data) - # fp.close() - # - # You might want to add some error checking :-) - else : - print "The file dialog was canceled before anything was selected" - - # Note that the current working dir didn't change. This is good since - # that's the way we set it up. - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def onOpen(self, evt=None): - """This method opens an existing file""" - print "Open a file: " - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'open' dialog, and allows multitple - # file selections as well. - # - # Finally, if the directory is changed in the process of getting files, this - # dialog is set up to change the current working directory to the path chosen. - dlg = wx.FileDialog( self, - message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.app_logic.file_open( path ) - else : - print "The file dialog was canceled before anything was selected" - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - app_logic = AppLogic() - f = TestFrame(app_logic, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - app = TestApp(False) - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_4.py b/slides_sources/old_versions/week-08.5/code/basic_app_4.py deleted file mode 100755 index 1d0cab65..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_4.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application - -This version adds a single button -""" - -import wx -import os - -#-------------------------------------------------------------- - -# This is how you pre-establish a file filter so that the dialog -# only shows the extension(s) you want it to. -wildcard = "Python source (*.py)|*.py|" \ - "Compiled Python (*.pyc)|*.pyc|" \ - "SPAM files (*.spam)|*.spam|" \ - "Egg file (*.egg)|*.egg|" \ - "All files (*.*)|*.*" - -#-------------------------------------------------------------- - -class AppLogic(object): - """ - A class to hold the application Application Logic. - - You generally don't want the real logic of the app mixed - in with the GUI - - In a real app, this would be a substantial collection of - modules, classes, etc... - """ - - def file_open(self, filename="default_name"): - """This method opens a file""" - print "Open a file: " - print "I'd be opening file: %s now"%filename - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class TestFrame(wx.Frame): - def __init__(self, app_logic, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - self.app_logic = app_logic - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - - saveasMenuItem = fileMenu.Append(wx.ID_ANY, "&Save As", "Create a new file") - self.Bind(wx.EVT_MENU, self.onSaveAs, saveasMenuItem ) - - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open an existing file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_ANY, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - ## add just a single button: - self.theButton = wx.Button(self, label="Push Me") - self.theButton.Bind(wx.EVT_BUTTON, self.onButton) - self.theButton.Bind(wx.EVT_RIGHT_DOWN, self.onRight) - - - def onButton(self, evt=None): - print "You pushed the button!" - evt.Skip() - def onRight(self, evt=None): - print "right click!" - evt.Skip() - - def onClose(self, evt=None): - print "close menu selected" - self.file_close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - def onSaveAs ( self, evt=None ): - """This method saves the file with a new name""" - - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'save' dialog. - # - # Unlike the 'open dialog' example found elsewhere, this example does NOT - # force the current working directory to change if the user chooses a different - # directory than the one initially set. - dlg = wx.FileDialog(self, - message="Save file as ...", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.SAVE ) - - # This sets the default filter that the user will initially see. Otherwise, - # the first filter in the list will be used by default. - dlg.SetFilterIndex(2) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - print "In onSaveAs, the path is %s" % path - # Normally, at this point you would save your data using the file and path - # data that the user provided to you, but since we didn't actually start - # with any data to work with, that would be difficult. - # - # The code to do so would be similar to this, assuming 'data' contains - # the data you want to save: - # - # fp = file(path, 'w') # Create file anew - # fp.write(data) - # fp.close() - # - # You might want to add some error checking :-) - else : - print "The file dialog was canceled before anything was selected" - - # Note that the current working dir didn't change. This is good since - # that's the way we set it up. - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def onOpen(self, evt=None): - """This method opens an existing file""" - print "Open a file: " - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'open' dialog, and allows multitple - # file selections as well. - # - # Finally, if the directory is changed in the process of getting files, this - # dialog is set up to change the current working directory to the path chosen. - dlg = wx.FileDialog( self, - message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.app_logic.file_open( path ) - else : - print "The file dialog was canceled before anything was selected" - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - app_logic = AppLogic() - f = TestFrame(app_logic, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - app = TestApp(False) - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_5.py b/slides_sources/old_versions/week-08.5/code/basic_app_5.py deleted file mode 100755 index 8861fd2c..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_5.py +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application - -This version puts the button on a Panel, where it belongs. -""" - -import wx -import os - -#-------------------------------------------------------------- - -# This is how you pre-establish a file filter so that the dialog -# only shows the extension(s) you want it to. -wildcard = "Python source (*.py)|*.py|" \ - "Compiled Python (*.pyc)|*.pyc|" \ - "SPAM files (*.spam)|*.spam|" \ - "Egg file (*.egg)|*.egg|" \ - "All files (*.*)|*.*" - -#-------------------------------------------------------------- - -class AppLogic(object): - """ - A class to hold the application Application Logic. - - You generally don't want the real logic of the app mixed - in with the GUI - - In a real app, this would be a substantial collection of - modules, classes, etc... - """ - - def file_open(self, filename="default_name"): - """This method opens a file""" - print "Open a file: " - print "I'd be opening file: %s now"%filename - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class ButtonPanel(wx.Panel): - def __init__(self, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - - #self.SetBackgroundColour(wx.Colour('red')) - ## add just a single button: - self.theButton = wx.Button(self, label="Push Me") - self.theButton.Bind(wx.EVT_BUTTON, self.onButton) - - def onButton(self, evt=None): - print "You pushed the button!" - -class TestFrame(wx.Frame): - def __init__(self, app_logic, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - self.app_logic = app_logic - - # put the Panel on the frame - self.buttonPanel = ButtonPanel(self) - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - - saveasMenuItem = fileMenu.Append(wx.ID_ANY, "&Save As", "Create a new file") - self.Bind(wx.EVT_MENU, self.onSaveAs, saveasMenuItem ) - - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open an existing file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_ANY, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - def onClose(self, evt=None): - print "close menu selected" - self.file_close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - def onSaveAs ( self, evt=None ): - """This method saves the file with a new name""" - - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'save' dialog. - # - # Unlike the 'open dialog' example found elsewhere, this example does NOT - # force the current working directory to change if the user chooses a different - # directory than the one initially set. - dlg = wx.FileDialog(self, - message="Save file as ...", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.SAVE ) - - # This sets the default filter that the user will initially see. Otherwise, - # the first filter in the list will be used by default. - dlg.SetFilterIndex(2) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - print "In onSaveAs, the path is %s" % path - # Normally, at this point you would save your data using the file and path - # data that the user provided to you, but since we didn't actually start - # with any data to work with, that would be difficult. - # - # The code to do so would be similar to this, assuming 'data' contains - # the data you want to save: - # - # fp = file(path, 'w') # Create file anew - # fp.write(data) - # fp.close() - # - # You might want to add some error checking :-) - else : - print "The file dialog was canceled before anything was selected" - - # Note that the current working dir didn't change. This is good since - # that's the way we set it up. - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def onOpen(self, evt=None): - """This method opens an existing file""" - print "Open a file: " - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'open' dialog, and allows multitple - # file selections as well. - # - # Finally, if the directory is changed in the process of getting files, this - # dialog is set up to change the current working directory to the path chosen. - dlg = wx.FileDialog( self, - message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.app_logic.file_open( path ) - else : - print "The file dialog was canceled before anything was selected" - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - app_logic = AppLogic() - f = TestFrame(app_logic, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - app = TestApp(False) - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_6.py b/slides_sources/old_versions/week-08.5/code/basic_app_6.py deleted file mode 100755 index 06b810d3..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_6.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application - -This version adds a BoxSizer for laying out two buttons on the panel -""" - -import wx -import os - -#-------------------------------------------------------------- - -# This is how you pre-establish a file filter so that the dialog -# only shows the extension(s) you want it to. -wildcard = "Python source (*.py)|*.py|" \ - "Compiled Python (*.pyc)|*.pyc|" \ - "SPAM files (*.spam)|*.spam|" \ - "Egg file (*.egg)|*.egg|" \ - "All files (*.*)|*.*" - -#-------------------------------------------------------------- - -class AppLogic(object): - """ - A class to hold the application Application Logic. - - You generally don't want the real logic of the app mixed - in with the GUI - - In a real app, this would be a substantial collection of - modules, classes, etc... - """ - - def file_open(self, filename="default_name"): - """This method opens a file""" - print "Open a file: " - print "I'd be opening file: %s now"%filename - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class ButtonPanel(wx.Panel): - def __init__(self, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - - ## add two buttons: - theButton1 = wx.Button(self, label="Push Me") - theButton1.Bind(wx.EVT_BUTTON, self.onButton) - - ## add two buttons: - theButton2 = wx.Button(self, label="Push Me Also") - theButton2.Bind(wx.EVT_BUTTON, self.onButton) - - ## do the layout - ## (try uncommenting the other, and see what happens...) - #S = wx.BoxSizer(wx.VERTICAL) - S = wx.BoxSizer(wx.HORIZONTAL) - - S.Add(theButton1, 0, wx.GROW | wx.ALL, 4) - S.Add(theButton2, 0, wx.GROW | wx.ALL, 4) - - self.SetSizerAndFit(S) - - def onButton(self, evt=None): - but_label = evt.EventObject.Label - print "You pushed buttons:", but_label - - -class TestFrame(wx.Frame): - def __init__(self, app_logic, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - self.app_logic = app_logic - - # put the Panel on the frame - self.buttonPanel = ButtonPanel(self) - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - - saveasMenuItem = fileMenu.Append(wx.ID_ANY, "&Save As", "Create a new file") - self.Bind(wx.EVT_MENU, self.onSaveAs, saveasMenuItem ) - - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open an existing file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_ANY, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - def onClose(self, evt=None): - print "close menu selected" - self.file_close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - def onSaveAs ( self, evt=None ): - """This method creates a new file""" - - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'save' dialog. - # - # Unlike the 'open dialog' example found elsewhere, this example does NOT - # force the current working directory to change if the user chooses a different - # directory than the one initially set. - dlg = wx.FileDialog(self, - message="Save file as ...", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.SAVE ) - - # This sets the default filter that the user will initially see. Otherwise, - # the first filter in the list will be used by default. - dlg.SetFilterIndex(2) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() - print "In onNew, the path is %s" % path - # Normally, at this point you would save your data using the file and path - # data that the user provided to you, but since we didn't actually start - # with any data to work with, that would be difficult. - # - # The code to do so would be similar to this, assuming 'data' contains - # the data you want to save: - # - # fp = file(path, 'w') # Create file anew - # fp.write(data) - # fp.close() - # - # You might want to add some error checking :-) - # - else : - print "The file dialog was canceled before anything was selected" - - # Note that the current working dir didn't change. This is good since - # that's the way we set it up. - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def onOpen(self, evt=None): - """This method opens an existing file""" - print "Open a file: " - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easilly - # be changed in your program. This is an 'open' dialog, and allows multitple - # file selections as well. - # - # Finally, if the directory is changed in the process of getting files, this - # dialog is set up to change the current working directory to the path chosen. - dlg = wx.FileDialog( self, - message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.app_logic.file_open( path ) - else : - print "The file dialog was canceled before anything was selected" - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - app_logic = AppLogic() - f = TestFrame(app_logic, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - app = TestApp(False) - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_7.py b/slides_sources/old_versions/week-08.5/code/basic_app_7.py deleted file mode 100755 index fc320458..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_7.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application - -This one adds another sizer to fix the layout -- and the WIT! -""" - - -import wx - -#--------------------------------------------------------------------------- - -# This is how you pre-establish a file filter so that file dialogs -# only show the extension(s) you want it to. -wildcard = "Python source (*.py)|*.py|" \ - "Compiled Python (*.pyc)|*.pyc|" \ - "SPAM files (*.spam)|*.spam|" \ - "Egg file (*.egg)|*.egg|" \ - "All files (*.*)|*.*" - -#--------------------------------------------------------------------------- - -class AppLogic(object): - """ - A class to hold the application Application Logic. - - You generally don't want the real logic of the app mixed - in with the GUI - - In a real app, this would be a substantial collection of - modules, classes, etc... - """ - def file_open(self, filename="default_name"): - """This method opens a file""" - print "Open a file: " - print "I'd be opening file: %s now"%filename - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class ButtonPanel(wx.Panel): - def __init__(self, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - - ## add a button: - theButton1 = wx.Button(self, label="Push Me") - theButton1.Bind(wx.EVT_BUTTON, self.onButton) - - ## add another button: - theButton2 = wx.Button(self, label="Push Me Also") - theButton2.Bind(wx.EVT_BUTTON, self.onButton) - - ## do the layout - buttonSizer = wx.BoxSizer(wx.VERTICAL) - - buttonSizer.Add((1,1), 1) # stretchable space - buttonSizer.Add(theButton1, 0, wx.GROW | wx.ALL, 4) - buttonSizer.Add(theButton2, 0, wx.GROW | wx.ALL, 4) - buttonSizer.Add((1,1), 3) # stretchable space - - ## need another sizer to get the horizonal placement right: - mainSizer = wx.BoxSizer(wx.HORIZONTAL) - mainSizer.Add((1,1), 1) # stretchable space - mainSizer.Add(buttonSizer, 0, wx.GROW) # the sizer with the buttons in it - mainSizer.Add((1,1), 1) # stretchable space - - self.SetSizer(mainSizer) - - def onButton(self, evt=None): - print "You pushed one of the buttons!" - - -class TestFrame(wx.Frame): - def __init__(self, app_logic, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - self.app_logic = app_logic - - # put the Panel on the frame - self.buttonPanel = ButtonPanel(self) - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open a file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_ANY, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - def onOpen(self, evt=None): - """This method opens an existing file""" - print "Open a file: " - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easily - # be changed in your program. This is an 'open' dialog, and allows multiple - # file selections as well. - # - # Finally, if the directory is changed in the process of getting files, this - # dialog is set up to change the current working directory to the path chosen. - dlg = wx.FileDialog( - self, message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.app_logic.file_open( path ) - else : - print "The file dialog was canceled before anything was selected" - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - def onClose(self, evt=None): - print "close menu selected" - self.app_logic.file_close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - app_logic = AppLogic() - f = TestFrame(app_logic, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - - app = TestApp(False) - ## set up the WIT -- to help debug sizers - import wx.lib.inspection - wx.lib.inspection.InspectionTool().Show() - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/code/basic_app_8.py b/slides_sources/old_versions/week-08.5/code/basic_app_8.py deleted file mode 100755 index eb305a60..00000000 --- a/slides_sources/old_versions/week-08.5/code/basic_app_8.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python - -""" -Example of the very basic, minimal framework for a wxPython application - -This adds a text box and reads the input from it, and writes it -to another text box -""" - - -import wx - -#--------------------------------------------------------------------------- - -# This is how you pre-establish a file filter so that file dialogs -# only show the extension(s) you want it to. -wildcard = "Python source (*.py)|*.py|" \ - "Compiled Python (*.pyc)|*.pyc|" \ - "SPAM files (*.spam)|*.spam|" \ - "Egg file (*.egg)|*.egg|" \ - "All files (*.*)|*.*" - -#--------------------------------------------------------------------------- - -class AppLogic(object): - """ - A class to hold the application Application Logic. - - You generally don't want the real logic of the app mixed - in with the GUI - - In a real app, this would be a substantial collection of - modules, classes, etc... - """ - def file_open(self, filename="default_name"): - """This method opens a file""" - print "Open a file: " - print "I'd be opening file: %s now"%filename - - def file_close(self): - """This method closes a file""" - print "Close a file: " - print "I'd be closing a file now" - - -class MainForm(wx.Panel): - def __init__(self, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - - ## add a button: - theButton1 = wx.Button(self, label="Push Me") - theButton1.Bind(wx.EVT_BUTTON, self.onButton) - - ## add a static text lable: - label1 = wx.StaticText(self, label="Input Box:") - - ## add a text control: - self.inTextControl = wx.TextCtrl(self) - - ## add another button: - theButton2 = wx.Button(self, label="GetData") - theButton2.Bind(wx.EVT_BUTTON, self.onGetData) - - ## add a static text lable: - label2 = wx.StaticText(self, label="Output Box:") - ## and another text control: - self.outTextControl = wx.TextCtrl(self, style=wx.TE_READONLY) - - - ## do the layout - buttonSizer = wx.BoxSizer(wx.VERTICAL) - - buttonSizer.Add(theButton1, 0, wx.GROW | wx.ALL, 4) - buttonSizer.Add(label1, 0, wx.ALIGN_LEFT | wx.TOP, 4) - buttonSizer.Add(self.inTextControl, 0, wx.GROW | wx.ALL, 4) - buttonSizer.Add((150, 10)) - buttonSizer.Add(theButton2, 0, wx.GROW | wx.ALL, 4) - buttonSizer.Add(label2, 0, wx.ALIGN_LEFT | wx.TOP, 4) - buttonSizer.Add(self.outTextControl, 0, wx.GROW | wx.ALL, 4) - - ## need another sizer to get the horizonal placement right: - mainSizer = wx.BoxSizer(wx.HORIZONTAL) - mainSizer.Add((1,1), 1) # stretchable space - mainSizer.Add(buttonSizer, 0, wx.ALIGN_TOP) # the sizer with the buttons in it - mainSizer.Add((1,1), 1) # stretchable space - - self.SetSizer(mainSizer) - - def onButton(self, evt=None): - print "You pushed one of the buttons!" - - def onGetData(self, evt=None): - print "get data button pressed" - contents = self.inTextControl.Value - print "the contents are:", contents - - self.outTextControl.Value = self.inTextControl.Value.upper() - - -class TestFrame(wx.Frame): - def __init__(self, app_logic, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) - - self.app_logic = app_logic - - # put the Panel on the frame - self.buttonPanel = MainForm(self) - - # Build up the menu bar: - menuBar = wx.MenuBar() - - fileMenu = wx.Menu() - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open a file" ) - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - closeMenuItem = fileMenu.Append(wx.ID_ANY, "&Close", "Close a file" ) - self.Bind(wx.EVT_MENU, self.onClose, closeMenuItem) - - exitMenuItem = fileMenu.Append(wx.ID_EXIT, "Exit", "Exit the application") - self.Bind(wx.EVT_MENU, self.onExit, exitMenuItem) - menuBar.Append(fileMenu, "&File") - - helpMenu = wx.Menu() - helpMenuItem = helpMenu.Append(wx.ID_HELP, "Help", "Get help") - menuBar.Append(helpMenu, "&Help") - - self.SetMenuBar(menuBar) - - def onOpen(self, evt=None): - """This method opens an existing file""" - print "Open a file: " - # Create the dialog. In this case the current directory is forced as the starting - # directory for the dialog, and no default file name is forced. This can easily - # be changed in your program. This is an 'open' dialog, and allows multiple - # file selections as well. - # - # Finally, if the directory is changed in the process of getting files, this - # dialog is set up to change the current working directory to the path chosen. - dlg = wx.FileDialog( - self, message="Choose a file", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.OPEN | wx.CHANGE_DIR - ) - - # Show the dialog and retrieve the user response. If it is the OK response, - # process the data. - if dlg.ShowModal() == wx.ID_OK: - # This returns a Python list of files that were selected. - path = dlg.GetPath() - print "I'd be opening file in onOpen ", path - self.app_logic.file_open( path ) - else : - print "The file dialog was canceled before anything was selected" - - # Destroy the dialog. Don't do this until you are done with it! - # BAD things can happen otherwise! - dlg.Destroy() - - def onClose(self, evt=None): - print "close menu selected" - self.app_logic.file_close() - - def onExit(self, evt=None): - print "Exit the program here" - print "The event passed to onExit is type ", type(evt), - self.Close() - - -class TestApp(wx.App): - def OnInit(self): - """ - App initilization goes here -- not much to do, in this case - """ - app_logic = AppLogic() - f = TestFrame(app_logic, parent=None) - f.Show() - - return True - -if __name__ == "__main__": - - app = TestApp(False) - ## set up the WIT -- to help debug sizers -# import wx.lib.inspection -# wx.lib.inspection.InspectionTool().Show() - app.MainLoop() - diff --git a/slides_sources/old_versions/week-08.5/presentation-wxpython.pdf b/slides_sources/old_versions/week-08.5/presentation-wxpython.pdf deleted file mode 100644 index 343eb788..00000000 Binary files a/slides_sources/old_versions/week-08.5/presentation-wxpython.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-08.5/presentation-wxpython.tex b/slides_sources/old_versions/week-08.5/presentation-wxpython.tex deleted file mode 100644 index 535d1827..00000000 --- a/slides_sources/old_versions/week-08.5/presentation-wxpython.tex +++ /dev/null @@ -1,1013 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Python Certificate: System Development]{System Development with Python:\\ DesktopGUIs: wxPython} -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{Nov 26, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - - -\section{Introduction} - -% --------------------------------------------- -\begin{frame}[fragile]{Desktop GUIs: wxPython} - -{\Large Desktop GUIs} - -\vfill -{\large Traditional Graphical User Interface Applications} - -\vfill -{\large Run entirely on local machine -- interactive, interface and logic code in one process} - -\vfill - -{\large Advantages:} -\begin{itemize} - \item Easier to write -- all in one program - \item Faster -- data/interface direct communication - \item Faster display: direct to screen (or even OpenGL, etc.) - \item Runs without network - \item Save/Manipulate local files - \item Familiar install/start/stop/run, etc. -\end{itemize} - -\end{frame} - - -\begin{frame}[fragile]{Python Options} - -{\Large Multiple GUI frameworks available:} - -\begin{itemize} - \item PyGTK - \item PyQT / PySide - \item TkInter - \item wxPython - \item PyGame - \item Native GUIs: Cocoa (PyObjC), PythonWin - \item Kivy for touchscreen (mobile) platforms - \item Some more minor ones... -\end{itemize} - -\end{frame} - - -\section{wxPython} - -\begin{frame}[fragile]{wxPython} - -{\Large Why wxPython?} - -\begin{itemize} - \item Python wrapper around C++ toolkit (wxWidget) - \item wxWidgets is a wrapper around \emph{native} toolkit: - \begin{itemize} - \item Windows: Win32 (64) - \item OS-X: Cocoa - \item Linux: GTK - \end{itemize} - \item Native look and feel - \item License: (modified) LGPL -\end{itemize} - -\vfill -{\Large Legacy: it was the best option for me when I first needed something...}\\ -See http://www.wxpython.org for more information - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Installing} - -{\Large wxPython is a big complicated build:\\ - can't do \verb`pip` or \verb`easy_install`} - -\vfill -{\Large Windows or OS-X:\\ -use the binaries on \url{http://wxpython.org/download.php}} - -\vfill -{\Large Linux: use your system's package} - -{\large NOTE: there are some issues with some packages:} -\begin{itemize} - \item May be old version - \item May use standard wx build -- more crash prone!\\ - (some run-time checking turned off) -\end{itemize} - - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Versions} - -\vfill -{\Large ``Stable'' version: 2.8.12.1}\\ -{\large (``stable'' means stable API, not less likely to crash)} - -\vfill -{\Large ``Development'' version: 2.9.4.0}\\ -{\large (Under active development, API may change (but not much)} - -\vfill -{\Large wx project very slow to do official releases -- You probably want to use the development version: it's getting more attention} - -\vfill -{\Large ``Phoenix'': next generation version: new bindings, Py3 support, etc.}\\ -{\large -- Still experimental}\\ -\url{http://wiki.wxpython.org/ProjectPhoenix} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Documentation} - -\vfill -{\Large ``Docs and Demos'': download these!}\\ - -\vfill -{\Large ``wxPython Demo'' -- run this!}\\ -{\large Examples of every Widget available} - -\vfill -{\Large Primary wx docs:}\\ -{\large Written for C++, with Python notes...}\\ -\url{http://wxpython.org/onlinedocs.php}\\ -This may help: \url{http://wiki.wxpython.org/C%2B%2BGuideForwxPythoneers} - -\vfill -{\large Semi-experimental Sphinx docs:}\\ -\url{http://xoomer.virgilio.it/infinity77/wxPython/} - -\vfill -{\Large The wxPython wiki: lots of good stuff here} -\url{http://wiki.wxpython.org/} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Some starting points} - - -\vfill -{\Large How to learn wxPython} -\url{http://wiki.wxpython.org/How%20to%20Learn%20wxPython} - -\vfill -{\Large wxPython Style Guide} -\url{http://wiki.wxpython.org/wxPython%20Style%20Guide} - -\vfill -{\Large The wxpython-users mailing list is a great resource (and great community):}\\ -\url{https://groups.google.com/forum/?fromgroups#!forum/wxpython-users} - -\vfill -{\large My own repository of samples:} -\url{https://github.com/PythonCHB/wxPythonDemos} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Pythonic code:} - - -\vfill -{\Large Over the years, wxPython has grown a number of things to make it more ``pythonic'' -- hide some of that C++ legacy} - -\vfill -{\Large Properties:} - -{\large The C++ classes are full of getters and setters:} -\begin{verbatim} -wxTextCtrl::SetValue -wxTextCtrl::GetValue -\end{verbatim} - -{\large These methods have been translated into properties for Python} -\begin{verbatim} -MyTextCtrl.Value = some_string -another_string = wxTextCtrl.Value -\end{verbatim} - -\vfill -(The Get/Set versions are still there, but it's klunkier code) -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Pythonic code:} - - -\vfill -{\Large Other Python options: some specific wx types can be accessed with standard python types:} - -\vfill -{\large \verb`wxPoint` --- \verb`(x,y)` ( tuple ) } - -\vfill -{\large \verb`wx.List` --- \verb`[1,2,3]` (python list) } - -\vfill -{\large \verb`wxSize` --- \verb`(w,h)` (tuple) } - -\vfill -{\large ....... } - - -\vfill -{\Large Using these makes your code cleaner and more pythonic} - -\end{frame} - -\section{Basic Structure} - -%------------------------------- -\begin{frame}[fragile]{Event-Driven programming} - -\vfill -{\large On app startup, the .MainLoop() method is called.} - -\vfill -{\large The mainloop takes control -- monitoring for events, then dispatching them} - -\vfill -{\large Events can come from the system, or user interaction: keyboard, mouse, etc.} - -\vfill -{\large All the work of your app is done in response to events} - -\vfill -{\large You only need to response to (Bind) the events you care about} - -\vfill -{\large Not so different than a web app, except events are finer-grained}\\ -(every mouse move, etc.) - - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{wx.Window} - -\vfill -{\Large Pretty much everything you see on the screen is a \verb`wx.Window`} - -\vfill -{\Large It is the superclass for all the ``widgets'', ``controls'', or whatever you want to call them} - -\vfill -{\Large It is essentially a rectangle on the screen that catches events} - -\vfill -{\Large You generally don't use it by iteself, though you may derive from it to make a new widget} - -\vfill -{\large(Historical Note: \verb|wxWidgets| was called \verb|wxWindows| -- until Microsoft threatened to sue them.)} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{wx.Window} - -\vfill -{\Large Since everything is a \verb`wx.Window`, it's good to know its methods and signature:} -\begin{verbatim} -def __init__(parent, - id=wx.ID_ANY, - pos=wx.DefaultPosition, - size=wx.DefaultSize, - style=0, - name=wx.PanelNameStr) -parent (wx.Window) -id (int) -pos (wx.Point) -size (wx.Size) -style (long) -name (string) -\end{verbatim} - -\vfill -\url{http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.Window.html} - -\end{frame} - - - -%------------------------------- -\begin{frame}[fragile]{wx.Window} - -\vfill -{\Large Methods types:} -\begin{itemize} - \item Appearance: Colors, Fonts, Labels, Styles - \item Geometry: Size, Position, IsShown, Move, etc - \item Layout: Sizers, etc. - \item Many others! -\end{itemize} - -\vfill -\url{http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.Window.html} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Event-Driven programming} - -\vfill -{\Large On app startup, the .MainLoop() method is called.} - -\vfill -{\Large The mainloop takes control -- monitoring for events, then dispatching them} - -\vfill -{\Large Events can come from the system, or user interaction: keyboard, mouse, etc.} - -\vfill -{\Large All the work of your app is done in response to events} - -\vfill -{\Large You only need to response to (Bind) the events you care about} - -\vfill -{\Large Not so different than a web app, except events are finer-grained}\\ -(every mouse move, etc.) - - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{wx.App} - -\vfill -{\Large Every wx app has a single wx.App instance:} - -\begin{verbatim} -app = wx.App(False) -frame = DemoFrame(None, title="Micro App") -frame.Show() -app.MainLoop() -\end{verbatim} - -(the \verb`False` means: ``don't re-direct stdout to a Window'') - -And you almost always start the `MainLoop` - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{wx.Frame} - -\vfill -{\Large \verb`wx.Frame` is a ``top level'' Window: One with a title bar, min-max buttons,etc.} - -\vfill -{\Large Most apps have a single \verb`wx.Frame` -- central interaction with the app.} - -\vfill -{\Large This is where menu bars, etc are placed, and often the core GUI logic of the app.} - - -\begin{verbatim} -class TestFrame(wx.Frame): - def __init__(self, *args, **kwargs): - kwargs.setdefault('title', "Simple test App") - wx.Frame.__init__(self, *args, **kwargs) -\end{verbatim} - - -\vfill -demo: \verb`code\basic_app_1.py` - -\end{frame} - -\section{controls} - -%------------------------------- -\begin{frame}[fragile]{Menus} - -\vfill -{\Large A \verb`wx.Frame` has a menu bar you can add items to:} - -\begin{verbatim} - # create the menu bar object - menuBar = wx.MenuBar() - - # add a menu to it - fileMenu = wx.Menu() - - # add an item to the menu - openMenuItem = fileMenu.Append(wx.ID_ANY, "&Open", "Open a file" ) - #bind a handler to the menu event - self.Bind(wx.EVT_MENU, self.onOpen, openMenuItem) - - self.SetMenuBar(menuBar) -\end{verbatim} - -\vfill -demo: \verb`code\basic_app_2.py` - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Event Handlers} - -\vfill -{\Large Event handlers have a common signature:} - -\vfill -\begin{verbatim} - def onOpen(self, evt=None): - print "open menu selected" - self.app_logic.file_open() -\end{verbatim} - -\vfill -{\large The second parameter is the \verb`wx.Event` object that initiated the call -- it holds information about the event that can be useful} - -\vfill -{\large I like to give the event parameter a default None, so the handler can be called from other parts of the code as well.} - -\vfill -demo: \verb`code\basic_app_2.py` - -\end{frame} - - - -%------------------------------- -\begin{frame}[fragile]{Common Dialogs} - -\vfill -{\Large wxPython provides a number of common Dialogs. These wrap the native ones where possible for a native look and feel.} - -\begin{itemize} - \item \verb`wx.MessageDialog` - \item \verb`wx.ColourDialog` - \item \verb`wx.FileDialog` - \item \verb`wx.PageSetupDialog` - \item \verb`wx.FontDialog` - \item \verb`wx.DirDialog` - \item \verb`wx.SingleChoiceDialog` - \item \verb`wx.TextEntryDialog` - \item ... -\end{itemize} - -\vfill -{\Large These do pretty much what you'd expect...} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{wx.FileDialog} - -\vfill -{\Large Example use of a common dialog: \verb`wx.FileDialog`}\\ - -\begin{verbatim} -dlg = wx.FileDialog(self, - message="Save file as ...", - defaultDir=os.getcwd(), - defaultFile="", - wildcard=wildcard, - style=wx.SAVE ) -if dlg.ShowModal() == wx.ID_OK: - path = dlg.GetPath() -else: - print "The file dialog was canceled before anything was selected" -dlg.Destroy() -\end{verbatim} - -\vfill -example: \verb`code/basic_app_3.py` -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Basic Widgets} - -\vfill -{\Large All the basic widgets (controls) you'd expect are there:} - -\begin{itemize} - \item Buttons - \item TextCtrl (Text Control) - \item Check Boxes - \item List Box - \item Combo Box - \item Slider - \item Spin Control - \item .... -\end{itemize} - -\vfill -{\Large Way too many to list here!} - -\vfill -{\Large See the docs and the Demo to find the one you need} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Using a Control} - -{\Large A Button is about as simple as it gets} - -\vfill -{\verb`__init__(parent, id, label="", pos=wx.DefaultPosition, ...)` } - -\vfill -{\Large Mostly the same as wx.Window, and other controls....} - -\begin{verbatim} -## add just a single button: -self.theButton = wx.Button(self, label="Push Me") -self.theButton.Bind(wx.EVT_BUTTON, self.onButton) - -## and give it an event handler -def onButton(self, evt=None): - print "You pushed the button!" -\end{verbatim} - -\vfill -code: \verb`code\basic_app_4.py` -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{wx.Panel} - -{\Large A \verb`wx.Panel` is a \verb`wx.Window` that you can put other controls on} - -\vfill -{\Large It supplies nifty things like tab traversal, etc.} - -\vfill -{\Large You \emph{can} put controls right on a \verb`wx.Frame` (we just did it), but a wx.Panel provided extra features, the ``normal'' look, and helps you organize and re-use your code} - -\vfill -{\Large Mostly the same as wx.Window, and other controls....} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{wx.Panel} - -\begin{verbatim} -class ButtonPanel(wx.Panel): - def __init__(self, *args, **kwargs): - wx.Panel.__init__(self, *args, **kwargs) - - self.theButton = wx.Button(self, label="Push Me") - self.theButton.Bind(wx.EVT_BUTTON, self.onButton) - def onButton(self, evt=None): - print "You pushed the button!" -\end{verbatim} -And use it in the Frame: -\begin{verbatim} - self.buttonPanel = ButtonPanel(self) -\end{verbatim} - -\vfill -code: \verb`code\basic_app_5.py` -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Control Layout} - -{\Large With more than one control, you need to figure out how to place them -and how big to make them} - -\vfill -{\Large You may have noticed that \verb`wx.Window` takes \verb`pos` and \verb`size` parameters} - -\vfill -{\Large You may have also noticed that I didn't use them.} - -\vfill -{\Large Why not?} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Absolute Positioning} - -{\LARGE Absolute positioning:} - -\vfill -{\Large Specifying the size and location of controls with pixel coordinates.} - -\vfill -{\Large This is a serious pain to do!} - -\vfill -{\Large Though it can be made a lot easier with GUI-building tools...} - -\vfill -{\Large So why not?} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Absolute Positioning} - -{\Large When you add or remove a control, the layout changes:}\\ -{\large -- recalculate all positions and sizes} - -\vfill -{\Large When you change the text on a control the layout changes:}\\ -{\large -- recalculate all positions and sizes} - -\vfill -{\Large When you try it on another platform the layout changes:}\\ -{\large -- recalculate all positions and sizes} - -\vfill -{\Large When the user changes default font size, the layout changes:}\\ -{\large -- recalculate all positions and sizes} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Sizers:} - -{\Large The alternative is ``Sizers''} - -\vfill -{\large \verb`wx.Sizer` is wx's system for automatically determining the size and location of controls} - -\vfill -{\large Instead of thinking in terms of what size and position a given control should be, you think in terms of how they relate to each other:} - -\vfill -{\large \emph{``I want a column of buttons all the same size along the left edge of the Panel''} } - -\vfill -{\large Sizers capture that logic and compute the sizes for you} - -\vfill -{\large They will re-size things for you when anything changes -- adding, removing, changing labels, re-sizing the Window, etc...} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{Sizers:} - -{\Large Sizers take a while to wrap your brain around...} - -\vfill -{\Large But it's worth the learning curve.} - - -\vfill -{\Large Nice discussion here:\\ -\url{http://wiki.wxpython.org/UsingSizers} } - -\vfill -{\large I have the graphic posted on the wall by my desk...} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Sizer Example} - -{\Large The Basic \verb`BoxSizer`}\\ -{\large -- Lays out a row or column of controls...} - -\vfill -\begin{verbatim} -Sizer.Add( window, proportion, flag, border ) - ## do the layout - S = wx.BoxSizer(wx.VERTICAL) - - S.Add(theButton1, 0, wx.GROW | wx.ALL, 4) - S.Add(theButton2, 0, wx.GROW | wx.ALL, 4) - - self.SetSizerAndFit(S) -\end{verbatim} -\vfill -code: \verb`code\basic_app_6.py` -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Nested Sizers} - -{\Large How do I get them centered both ways?}\\ -{\large -- Nest a vertical sizer inside a horizonal one}\\ -{\large -- And add stretchable spacers...} - -\vfill -\begin{verbatim} -buttonSizer = wx.BoxSizer(wx.VERTICAL) - -buttonSizer.Add(theButton1, 0, wx.GROW | wx.ALL, 4) -buttonSizer.Add(theButton2, 0, wx.GROW | wx.ALL, 4) - -mainSizer = wx.BoxSizer(wx.HORIZONTAL) -mainSizer.Add((1,1), 1) # stretchable space -mainSizer.Add(buttonSizer, 0, wx.ALIGN_CENTER) # the sizer with the buttons in it -mainSizer.Add((1,1), 1) # stretchable space -\end{verbatim} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Widget Inspection Tool} - -{\Large How do I keep all this straight?}\\ - -\vfill -{\large The Widget Inspection Tool (WIT) is very handy:} - -\vfill -\begin{verbatim} - app = TestApp(False) - ## set up the WIT -- to help debug sizers - import wx.lib.inspection - wx.lib.inspection.InspectionTool().Show() - app.MainLoop() -\end{verbatim} - -(you can also bring it up from a menu event, or...) - -\vfill -code: \verb`code\basic_app_7.py` - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Other Sizers} - -{\Large Sizers for laying out stuff in grids...}\\ - -\vfill -{\large \verb`wx.GridSizer`} - -\vfill -{\large \verb`wx.FlexGridSizer`} - -\vfill -{\large \verb`wx.GridBagSizer`} - -\vfill -(you can do it all with a GridBagSizer) - -\vfill -See the docs for info. - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Hierarchies...} - -{\Large wxPython has multiple independent hierarchies ...}\\ - -\vfill -{\large The nested parent-child relationship:} -\begin{itemize} - \item every \verb`wx.Window` has a parent - \item every \verb`wx.Window` has zero or more children -\end{itemize} - -{\large The class Hierarchy} -\begin{itemize} - \item sub classes of \verb`wx.Window` - \item classes with instances as attributes -\end{itemize} - -{\large The Layout Hierarchy} -\begin{itemize} - \item Sizers within Sizers... - \item Arbitrarily deep. -\end{itemize} - -\vfill -{\large Each of these takes care of different concerns:\\ - confusing but powerful} -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{Accessing inputs} - -{\Large Much of the point of a GUI is to collect data from the user.} - -\vfill -{\large So you need to be able to access what s/he has input} - -\begin{verbatim} - ## add a text control: - self.textControl = wx.TextCtrl(self) - - def onGetData(self, evt=None): - print "get data button pressed" - contents = self.textControl.Value - print "the contents are:", contents -\end{verbatim} - -{\large Most controls have a \verb`.Value` property} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{Setting Values} - -{\Large You also want to display data...} - -\vfill -{\large So you need to be able to set the values, too:} - -\begin{verbatim} -## and another text control: -self.outTextControl = wx.TextCtrl(self, - style=wx.TE_READONLY) - -def onGetData(self, evt=None): - self.outTextControl.Value = self.inTextControl.Value -\end{verbatim} - -{\large You can set the \verb`.Value` property too...} - -\vfill -{\large example: \verb`code\basic_app8.py`} - -\end{frame} - - -%--------------------------------- -\begin{frame}[fragile]{Code-generated GUIs...} - -\vfill -{\large You shouldn't write the same repetitive code for a GUI..} - -\vfill -{\large You may need to build a GUI to match data at run time.} - -\vfill -{\large Lots of ways to do that with wxPython -- Sizers help a lot.} - -\vfill -{\large Try to do it whenever you find yourself writing repetitive code...} - -\vfill -{\large The key is how to do the event Binding} -\begin{verbatim} - def OnButton(self, evt): - label = evt.GetEventObject().GetLabel() - - do_somethign_with_label(label) -\end{verbatim} -\vfill -example: \verb`code/CalculatorDemo.py` -\end{frame} - - -%--------------------------------- -\begin{frame}[fragile]{Code-generated GUIs...} - -\vfill -{\Large The ``lambda trick''} - -\vfill -{\large -- a way to pass custom data to an event handler:} - -\vfill -{\large The key is how to do the event Binding} -\begin{verbatim} -for name in ["first", "second", "third"]: - btn = wx.Button(self, label=name) - btn.Bind(wx.EVT_BUTTON, - lambda evt, n=name: self.OnButton(evt, n) ) -.... -def OnButton(self, Event, name): - print "In OnButton:", name - -\end{verbatim} - -\vfill -\url{http://wiki.wxpython.org/Passing%20Arguments%20to%20Callbacks} -\end{frame} - - -\section{Miscellaneous} - -%------------------------------- -\begin{frame}[fragile]{Long Running Tasks} - -\vfill -{\Large The UI is locked up while an event is being handled} - -\vfill -{\Large So you want all event handlers to run fast.} - -\vfill -{\Large But what if there is significant work to do?} - -\vfill -{\Large Enter: threading and multi-processing} - -\vfill -{\Large But: wxPython is not thread-safe: almost all wx methods must be called from within the same thread.} - -\vfill -{\Large Thread-safe operations: Creating and Posting Events} - - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{CallAfter} - -\vfill -{\Large Easiest way to communicate with threads:\\ - \verb`wx.CallAfter`} - -\vfill -{\Large Puts an event on the event stack, calls the designated function or method when the stack is cleared:} - -\begin{verbatim} -wx.CallAfter(function_to_call, *args, **kwargs) - -# *args, **kwargs are passed on to FunctionToCall -\end{verbatim} - -{\large (see also: \verb`wx.CallLater()`) } - -\vfill -\url{http://wiki.wxpython.org/LongRunningTasks} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{BILS} - -\vfill -{\Large {\bf B}rowser {\bf I}nterface, {\bf L}ocal {\bf S}erver} -\vfill - -\vfill -{\Large Web app: Server runs on local machine} -\vfill - -\vfill -{\Large Browser is the interface -- but all running local} - -\vfill -{\Large Can wrap the Browser window in a desktop app: Chrome Embedded Framework, wxWebkit, etc.} - -\vfill -{\Large Good way to get both a web app and desktop app with one codebase} - -\vfill -{\Large Example: Cameo Chemicals} - -\vfill -(PyCon 2009: Browser Interface, Local Server Application) -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\Large Make a very simple address book app:} - -\begin{enumerate} - \item Really basic data model is in \verb`address_book_data.py` - \item Finish the form to edit an entry -- subclass of a \verb`wx.Panel` (\verb`entry_form.py`) - \item The form goes on a \verb`wx.Frame` (\verb`address_book_app.py`) \\ - add a way to switch between entries (\verb`switcher.py`) - \item Add a ``new record'' button - \item Add file--save and file--open menus to the frame - \item Add some validation, better layout, etc.... -\end{enumerate} - -\vfill -\verb`code\address_book\` - -\end{frame} - - -\end{document} - - diff --git a/slides_sources/old_versions/week-08/code/GeneratorLAB.html b/slides_sources/old_versions/week-08/code/GeneratorLAB.html deleted file mode 100644 index 0b287bc8..00000000 --- a/slides_sources/old_versions/week-08/code/GeneratorLAB.html +++ /dev/null @@ -1,375 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> -<meta name="generator" content="Docutils 0.11: http://docutils.sourceforge.net/" /> -<title>Generator LAB - - - -
        -

        Generator LAB

        - -

        Write some generators:

        -

        (test code in test_generator.py)

        -
        -

        Sum of the integers:

        -

        keep adding the next integer

        -

        0 + 1 + 2 + 3 + 4 + 5 + ...

        -

        so the sequence is:

        -

        0, 1, 3, 6, 10, 15 .....

        -
        -
        -

        Doubler

        -

        Each value is double the previous value:

        -

        1, 2, 4, 8, 16, 32,

        -
        -
        -

        Fibonacci sequence

        -

        The fibonaccisequenc as a generator:

        -

        f(n) = f(n-1) + f(n-2)

        -

        1, 1, 2, 3, 5, 8, 13, 21, 34...

        -
        -
        -

        Prime numbers

        -

        Generate the prime numbers (numbers only divisible by them self and 1):

        -

        2, 3, 5, 7, 11, 13, 17, 19, 23...

        -
        -
        -

        Others to try:

        -

        Try x^2, x^3, counting by threes, x^e, counting by minus seven, ...

        -
        -
        - - diff --git a/slides_sources/old_versions/week-08/code/GeneratorLAB.rst b/slides_sources/old_versions/week-08/code/GeneratorLAB.rst deleted file mode 100644 index c82c179a..00000000 --- a/slides_sources/old_versions/week-08/code/GeneratorLAB.rst +++ /dev/null @@ -1,47 +0,0 @@ -Generator LAB -################# - -Write some generators: - -(test code in ``test_generator.py``) - -Sum of the integers: -====================== - -keep adding the next integer - -0 + 1 + 2 + 3 + 4 + 5 + ... - -so the sequence is: - -0, 1, 3, 6, 10, 15 ..... - -Doubler -========= - -Each value is double the previous value: - -1, 2, 4, 8, 16, 32, - -Fibonacci sequence -=================== - -The fibonaccisequenc as a generator: - -f(n) = f(n-1) + f(n-2) - -1, 1, 2, 3, 5, 8, 13, 21, 34... - -Prime numbers -=============== - -Generate the prime numbers (numbers only divisible by them self and 1): - -2, 3, 5, 7, 11, 13, 17, 19, 23... - -Others to try: -================ - -Try x^2, x^3, counting by threes, x^e, counting by minus seven, ... - - diff --git a/slides_sources/old_versions/week-08/code/circle.py b/slides_sources/old_versions/week-08/code/circle.py deleted file mode 100644 index 976ea519..00000000 --- a/slides_sources/old_versions/week-08/code/circle.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python - -""" -circle class -- - -fill this in so it will pass all the tests. -""" - -import math - -class Circle(object): - pass diff --git a/slides_sources/old_versions/week-08/code/circle_solution1.py b/slides_sources/old_versions/week-08/code/circle_solution1.py deleted file mode 100644 index dc45ba22..00000000 --- a/slides_sources/old_versions/week-08/code/circle_solution1.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -""" -circle class -- my solution to the firt part of the exercise - -test code to run it is in test_circle1.py -""" - -import math - -class Circle(object): - def __init__(self, radius): - self.radius = radius - - def _get_d(self): - return self.radius * 2 - def _set_d(self, d): - self.radius = d / 2.0 - diameter = property(_get_d, _set_d, doc="The diameter of the circle") - - def _get_area(self): - return math.pi * self.radius**2 - area = property(_get_area, doc="The area of the circle") - - # alternate constructor that takes diameter - def from_diameter(klass, d): - return klass(d / 2.0) - from_diameter = classmethod(from_diameter) - - diff --git a/slides_sources/old_versions/week-08/code/circle_solution2.py b/slides_sources/old_versions/week-08/code/circle_solution2.py deleted file mode 100644 index 35725ee0..00000000 --- a/slides_sources/old_versions/week-08/code/circle_solution2.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python - -""" -circle class -- my solution to the second part of the exercise - -test code to run it is in test_circle2.py -""" - -import math - -class Circle(object): - def __init__(self, radius): - self.radius = radius - - def _get_d(self): - return self.radius * 2 - def _set_d(self, d): - self.radius = d / 2.0 - diameter = property(_get_d, _set_d, doc="The diameter of the circle") - - def _get_area(self): - return math.pi * self.radius**2 - area = property(_get_area, doc="The area of the circle") - - # alternate constructor that takes diameter - def from_diameter(klass, d): - return klass(d / 2.0) - from_diameter = classmethod(from_diameter) - - ## The magic methods: - def __str__(self): - return "Circle with radius: %f"%self.radius - - def __repr__(self): - return "Circle(%s)"%self.radius - - def __add__(self, other): - return Circle(self.radius + other.radius) - - def __mul__(self, factor): - return Circle(self.radius * factor) - - ## comparisons - def __eq__(self, other): - return self.radius == other.radius - def __ne__(self, other): - return self.radius != other.radius - def __gt__(self, other): - return self.radius > other.radius - def __ge__(self, other): - return self.radius >= other.radius - def __lt__(self, other): - return self.radius < other.radius - def __le__(self, other): - return self.radius <= other.radius - - # ## or, in this simple case: - # def __cmp__(self, other): - # return cmp(self.radius, other.radius) diff --git a/slides_sources/old_versions/week-08/code/class_method.py b/slides_sources/old_versions/week-08/code/class_method.py deleted file mode 100644 index fcfc6795..00000000 --- a/slides_sources/old_versions/week-08/code/class_method.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -""" -example of a class method -""" - -class C(object): - def __init__(self, x, y): - self.x = x - self.y = y - - def a_class_method(klass, y): - print "in a_class_method", klass - return klass( y, y**2 ) - a_class_method = classmethod(a_class_method) - -class C2(C): - pass - - -if __name__ == "__main__": - - c = C(3, 4) - print type(c), c.x, c.y - - c2 = C.a_class_method(3) - print type(c2), c2.x, c2.y - - c3 = C2.a_class_method(2) - \ No newline at end of file diff --git a/slides_sources/old_versions/week-08/code/generator_solution.py b/slides_sources/old_versions/week-08/code/generator_solution.py deleted file mode 100644 index 738403e8..00000000 --- a/slides_sources/old_versions/week-08/code/generator_solution.py +++ /dev/null @@ -1,49 +0,0 @@ -import math - - -def intsum(): # 1 + 2 + 3 + 4 + 5... - """ - simplest solution - """ - a = b = 0 - while True: - yield b - a += 1 - b = b + a - -def intsum2(): # 1 + 2 + 3 + 4 + 5... - """ - takes advantage of some clever math - """ - a = 0 - while True: - yield (a * (a + 1)) / 2 - a += 1 - - -def doubler(): # 1, 2, 4, 8, 16, 32, 64... - a = 1 - while True: - yield a - a = a * 2 - - -def fib(): # 1, 1, 2, 3, 5, 8, 13, 21, 34... - a, b = 0, 1 - while True: - yield b - a, b = b, a + b - -def prime(): # 2, 3, 5, 7, 11, 13, 17, 19, 23... - a = 2 - while True: - yield a - p = False - while not p: # while not prime - a += 1 # try the next integer - p = True # assume it is prime... - for x in xrange(2, int(math.floor(math.sqrt(a))) + 1): - if a % x == 0: - p = False # ...unless it isn't - break - diff --git a/slides_sources/old_versions/week-08/code/iterator_2_solution.py b/slides_sources/old_versions/week-08/code/iterator_2_solution.py deleted file mode 100644 index 1560573f..00000000 --- a/slides_sources/old_versions/week-08/code/iterator_2_solution.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python - -""" -Simple iterator examples -""" - -class IterateMe_2(object): - """ - Almost a replacement for xrange: - - Iterate_2(start, stop, step=1) - - returns the sequence of numbers from start (inclusive) to stop (exclusive), - skipping every step number - ( like xrange(start, stop, step) ) - - """ - def __init__(self, start, stop, step=1): - self.current = start-step - self.stop = stop - self.step = step - def __iter__(self): - return self - def next(self): - self.current += self.step - if self.current < self.stop: - return self.current - else: - raise StopIteration - - -if __name__ == "__main__": - - print "second version" - for i in IterateMe_2(0, 5): - print i - - print "second version with a different start" - for i in IterateMe_2(4, 7): - print i - - print "second version with a different step" - for i in IterateMe_2(2, 20, 2): - print i - - print "But what if we break out of it:" - it = IterateMe_2(2, 20, 2) - for i in it: - if i > 10: - break - print i - - print "And then pick up again" - for i in it: - print i - - - diff --git a/slides_sources/old_versions/week-08/code/iterator_3_solution.py b/slides_sources/old_versions/week-08/code/iterator_3_solution.py deleted file mode 100644 index 4f477f63..00000000 --- a/slides_sources/old_versions/week-08/code/iterator_3_solution.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python - -""" -Simple iterator examples -""" - -class IterateMe_3(object): - """ - Almost a replacement for xrange: - - IterateMe_3 (start, stop, step=1) - - returns the sequence of numbers from start (inclusive) to stop (exclusive), - skipping every step number - - ( like xrange(start, stop, step) ) - - This version re-sets itself when used again. - """ - def __init__(self, start, stop, step=1): - self.start = start - self.stop = stop - self.step = step - self.current = start-step - def __iter__(self): - self.current = self.start-self.step - return self - def next(self): - self.current += self.step - if self.current < self.stop: - return self.current - else: - raise StopIteration - -if __name__ == "__main__": - - print "Test the usual" - for i in IterateMe_3(3, 11, 2): - print i - - print "This one is different when broken out of" - it = IterateMe_3(3, 11, 2) - for i in it: - if i > 8: - break - print i - - print "we pick up again from the beginning" - for i in it: - print i - diff --git a/slides_sources/old_versions/week-08/code/properties_example.py b/slides_sources/old_versions/week-08/code/properties_example.py deleted file mode 100644 index ab5e6745..00000000 --- a/slides_sources/old_versions/week-08/code/properties_example.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -""" -example code for properties - -NOTE: if your getters and setters are this simple: don't do this! - -""" - -class C(object): - _x = None - def getx(self): - return self._x - def setx(self, value): - self._x = value - def delx(self): - del self._x - x = property(getx, setx, delx, "docstring") - -if __name__ == "__main__": - c = C - c.x = 5 - print c.x - diff --git a/slides_sources/old_versions/week-08/code/static_method.py b/slides_sources/old_versions/week-08/code/static_method.py deleted file mode 100644 index 674c9d59..00000000 --- a/slides_sources/old_versions/week-08/code/static_method.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python - -""" -examples of static and class methods -""" - -class C(object): - - def a_static_method(a, b): - print "in a_static_method" - return a+b - a_static_method = staticmethod(a_static_method) - - def test(self): - return self.a_static_method(2,3) - -if __name__ == "__main__": - - print C.a_static_method(3,4) - - c = C() - - print c.a_static_method(4,5) - - \ No newline at end of file diff --git a/slides_sources/old_versions/week-08/code/test_circle1.py b/slides_sources/old_versions/week-08/code/test_circle1.py deleted file mode 100644 index f7e0203c..00000000 --- a/slides_sources/old_versions/week-08/code/test_circle1.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - -""" -code that tests the circle class defined in circle.py - -can be run with py.test -""" - -import pytest # used for the exception testing - -import math - - -from circle import Circle -#from circle_solution1 import Circle - -def test_create(): - c = Circle(4) - - assert c.radius == 4 - -def test_change_radius(): - c = Circle(3) - c.radius = 4 - - assert c.radius == 4 - -def test_diameter(): - c = Circle(4) - - assert c.diameter == 8 - -def test_change_diameter(): - c = Circle(2) - - assert c.radius == 2 - assert c.diameter == 4 - - c.diameter = 6 - assert c.radius == 3 - assert c.diameter == 6 - -def test_area(): - c = Circle(4) - - assert c.area == math.pi*16 - -def test_set_area(): - c = Circle(4) - - with pytest.raises(AttributeError): - c.area = 44 - - -## the extra credit: classmethod: - -# def test_alternate_constructor(): -# c = Circle.from_diameter(8) - -# assert c.diameter == 8 -# assert c.radius == 4 - - - - - diff --git a/slides_sources/old_versions/week-08/code/test_circle2.py b/slides_sources/old_versions/week-08/code/test_circle2.py deleted file mode 100644 index 19453380..00000000 --- a/slides_sources/old_versions/week-08/code/test_circle2.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python - -""" -code that tests the circle class defined in circle.py - -This version adds more tests - -(circle_solution_2 should pass them...) - -can be run with py.test -""" - -import pytest # used for the exception testing - -import math - - -from circle import Circle -#from circle_solution2 import Circle - -def test_create(): - c = Circle(4) - - assert c.radius == 4 - -def test_change_radius(): - c = Circle(3) - c.radius = 4 - - assert c.radius == 4 - -def test_diameter(): - c = Circle(4) - - assert c.diameter == 8 - -def test_change_diameter(): - c = Circle(2) - - assert c.radius == 2 - assert c.diameter == 4 - - c.diameter = 6 - assert c.radius == 3 - assert c.diameter == 6 - -def test_area(): - c = Circle(4) - - assert c.area == math.pi*16 - -def test_set_area(): - c = Circle(4) - - with pytest.raises(AttributeError): - c.area = 44 - - -## the extra credit: classmethod: - -# def test_alternate_constructor(): -# c = Circle.from_diameter(8) - -# assert c.diameter == 8 -# assert c.radius == 4 - -## the magic methods: - -def test_str(): - c = Circle(3) - - assert str(c) == 'Circle with radius: 3.000000' - -def test_repr(): - c = Circle(3) - - assert repr(c) == 'Circle(3)' - -def test_addition(): - c1 = Circle(2) - c2 = Circle(3) - c3 = c1 + c2 - - assert c3.radius == 5 - -def test_multiplication(): - c1 = Circle(2) - c3 = c1 * 4 - - assert c3.radius == 8 - -def test_equal(): - c1 = Circle(3) - c2 = Circle(3.0) - - assert c1 == c2 - assert c1 <= c2 - assert c1 >= c2 - -def test_not_equal(): - c1 = Circle(2.9) - c2 = Circle(3.0) - - assert c1 != c2 - -def test_greater(): - c1 = Circle(2) - c2 = Circle(3) - - assert c2 > c1 - assert c2 >= c1 - -def test_less(): - c1 = Circle(2) - c2 = Circle(3) - - assert c1 < c2 - assert c1 <= c2 - - - - - - - - - - diff --git a/slides_sources/old_versions/week-08/code/test_generator.py b/slides_sources/old_versions/week-08/code/test_generator.py deleted file mode 100644 index 1cc03475..00000000 --- a/slides_sources/old_versions/week-08/code/test_generator.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -test_generator.py - -tests the solution to the generator lab -""" - -import generator_solution as gen - -def test_intsum(): - - g = gen.intsum() - - assert g.next() == 0 - assert g.next() == 1 - assert g.next() == 3 - assert g.next() == 6 - assert g.next() == 10 - assert g.next() == 15 - -def test_intsum2(): - - g = gen.intsum2() - - assert g.next() == 0 - assert g.next() == 1 - assert g.next() == 3 - assert g.next() == 6 - assert g.next() == 10 - assert g.next() == 15 - - -def test_doubler(): - - g = gen.doubler() - - assert g.next() == 1 - assert g.next() == 2 - assert g.next() == 4 - assert g.next() == 8 - assert g.next() == 16 - assert g.next() == 32 - - for i in range(10): - j = g.next() - - assert j == 2**15 - -def test_fib(): - g = gen.fib() - - assert g.next() == 1 - assert g.next() == 1 - assert g.next() == 2 - assert g.next() == 3 - assert g.next() == 5 - assert g.next() == 8 - assert g.next() == 13 - assert g.next() == 21 - -def test_prime(): - g = gen.prime() - - assert g.next() == 2 - assert g.next() == 3 - assert g.next() == 5 - assert g.next() == 7 - assert g.next() == 11 - assert g.next() == 13 - assert g.next() == 17 - assert g.next() == 19 - assert g.next() == 23 - - - - diff --git a/slides_sources/old_versions/week-08/code/test_iterator.py b/slides_sources/old_versions/week-08/code/test_iterator.py deleted file mode 100644 index 78d91795..00000000 --- a/slides_sources/old_versions/week-08/code/test_iterator.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python - -""" -tests for the iterator solutions -""" - -from iterator_1 import IterateMe_1 -from iterator_2_solution import IterateMe_2 -from iterator_3_solution import IterateMe_3 - -def test_1(): - l = [] - for i in IterateMe_1(4): - l.append(i) - print l - assert l == [0, 1, 2, 3] - -def test_3a(): - l = [] - for i in IterateMe_3(1, 4): - l.append(i) - print l - assert l == [1, 2, 3] - -def test_3b(): - l = [] - for i in IterateMe_3(0, 3): - l.append(i) - print l - assert l == [0, 1, 2] - -def test_3c(): - l = [] - for i in IterateMe_3(2, 10, 2): - l.append(i) - print l - assert l == [2, 4, 6, 8] - -def test_3_break(): - """ - this tests if the iterator re-sets itself when called again. - """ - iter = IterateMe_3(2,10,2) - - l = [] - for i in iter: - l.append(i) - if i > 4: break - print l - assert l == [2, 4, 6] - - ## doing it again should give the same result - ## i.e. the iterator should reset when it its used again - l = [] - for i in iter: - l.append(i) - if i > 4: break - print l - assert l == [2, 4, 6] - - diff --git a/slides_sources/old_versions/week-08/code/vector.py b/slides_sources/old_versions/week-08/code/vector.py deleted file mode 100644 index 56ee2404..00000000 --- a/slides_sources/old_versions/week-08/code/vector.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Vector type with +, * redefined as vector addition and dot product -From Jon Jacky's Intro to Python course: - http://staff.washington.edu/jon/python-course/ -""" - - -class vector(list): - def __repr__(self): - """ - String representation, uses list (superclass) representation - """ - return 'vector(%s)' % super(vector, self).__repr__() - - def __add__(self, v): - """ - redefine + as element-wise vector sum - """ - assert len(self) == len(v) - return vector([x1 + x2 for x1, x2 in zip(self, v)]) - - def __mul__(self, v): - """ - redefine * as vector dot product - """ - assert len(self) == len(v) - return sum([x1 * x2 for x1, x2 in zip(self, v)]) - -l1 = [1, 2, 3] -l2 = [4, 5, 6] -v1 = vector(l1) -v2 = vector(l2) - -if __name__ == '__main__': - print 'l1' - print l1 - print 'l1 + l2' - print l1 + l2 - # print l1 * l2 # TypeError - print 'zip(l1, l2)' - print zip(l1, l2) - print 'v1' - print v1 - print 'v1 + v2' - print v1 + v2 - print 'v1 * v2' - print v1 * v2 diff --git a/slides_sources/old_versions/week-08/code/yield_example.py b/slides_sources/old_versions/week-08/code/yield_example.py deleted file mode 100644 index fc16c01c..00000000 --- a/slides_sources/old_versions/week-08/code/yield_example.py +++ /dev/null @@ -1,22 +0,0 @@ -def counter(): - print 'counter: starting counter' - i = -3 - while i < 3: - i = i + 1 - print 'counter: yield', i - yield i - - - -if __name__ == '__main__': - print "the generator function:" - print repr(counter) - print "call generator function" - - c = counter() - print "the generator:" - print repr(c) - - print 'iterate' - for item in c: - print 'received:', item diff --git a/slides_sources/old_versions/week-08/code/yield_xrange.py b/slides_sources/old_versions/week-08/code/yield_xrange.py deleted file mode 100644 index ba75f3d7..00000000 --- a/slides_sources/old_versions/week-08/code/yield_xrange.py +++ /dev/null @@ -1,49 +0,0 @@ -def y_xrange(start, stop, step=1): - """ - a version of xrange, using a generator - """ - i = start - while i < stop: - yield i - i += step - - -def y_xrange_2(start, stop=None, step=1): - """ - a version of xrange, using a generator - - supports the full set of options - """ - if stop is None: - stop = start - start = 0 - i = start - while i < stop: - yield i - i += step - - - - -if __name__ == '__main__': - print "y_xrange(0, 5)" - for item in y_xrange(0, 5): - print item - -# print "y_xrange(-4, 4, 2)" -# for item in y_xrange(-4, 4, 2): -# print item -# -# print "y_xrange_2(4)" -# for item in y_xrange_2(4): -# print item -# -# print "y_xrange_2(2, 5)" -# for item in y_xrange_2(2, 5): -# print item -# -# print "y_xrange_2(10, step=2)" -# for item in y_xrange_2(10, step=2): -# print item - - \ No newline at end of file diff --git a/slides_sources/old_versions/week-08/presentation-week-08.pdf b/slides_sources/old_versions/week-08/presentation-week-08.pdf deleted file mode 100644 index 15bdc4a9..00000000 Binary files a/slides_sources/old_versions/week-08/presentation-week-08.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-08/presentation-week-08.tex b/slides_sources/old_versions/week-08/presentation-week-08.tex deleted file mode 100644 index 9fab9b53..00000000 --- a/slides_sources/old_versions/week-08/presentation-week-08.tex +++ /dev/null @@ -1,734 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Intro to Python: Week 8]{Introduction to Python\\ -More OO: Special methods, magic methods\\ -Iterators and Generators} -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{November 19, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - -% --------------------------------------------- -\begin{frame}{Schedule...} - -\vfill -{\Large Three more classes (including this one)!} - -\vfill -{\Large No class next week: Thanksgiving!} - -\vfill -{\Large Extra time to work on project...} - -\end{frame} - -% --------------------------------------------- -\begin{frame}{Desktop GUIs} - -\vfill -{\Large A number of people are interested in desktop GUIs} - -\vfill -{\Large No time to cover that in class} - -\vfill -{\Large Extra class T-day week on wxPython?} - -\end{frame} - - -\section{Review/Questions} - -% --------------------------------------------- -\begin{frame}{Review of Previous Class} - -\begin{itemize} - \item Object oriented programing - \item Classes, subclasses, instances. - \item The html generator -\end{itemize} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning talks today:} - -\vfill -{\Large -Luke Cypret -\vfill -Blane Moore -\vfill -Brent Parrish -\vfill -} - -\vfill - -\end{frame} - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Properties} - -% --------------------------------------------- -\begin{frame}[fragile]{Accessing Attributes} - -{\Large One of the strengths of Python is lack of clutter} - -\vfill -{\Large Simple attributes:} - -\begin{verbatim} -In [5]: class C(object): - def __init__(self): - self.x = 5 -In [6]: c = C() -In [7]: c.x -Out[7]: 5 -In [8]: c.x = 8 -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Getter and Setters?} - -{\Large What if you need to add behavior later?} - -\begin{itemize} - \item do some calculation - \item check data validity - \item keep things in sync -\end{itemize} - -\end{frame} - - -\begin{frame}[fragile]{Getter and Setters?} - -\begin{verbatim} -class C(object): - def get_x(self): - return self.x - def set_x(self, x): - self.x = x ->>> c = C() ->>> c.get_x() ->>> 5 ->>> c.set_x(8) ->>> c.get_x() ->>> 8 -\end{verbatim} -{\Large Ugly and verbose -- Java?} - -\url{http://dirtsimple.org/2004/12/python-is-not-java.html} - -\end{frame} - -\begin{frame}[fragile]{properties} - -{ \Large When (and if) you need them: } - -\begin{verbatim} -class C(object): - def _getx(self): - return self._x - def _setx(self, value): - self._x = value - def _delx(self): - del self._x - x = property(_getx, _setx, _delx, doc="docstring") -\end{verbatim} -{\Large Interface is still like simple attribute access} - -\vfill -(demo: \verb|properties_sample.py| ) -\end{frame} - -\begin{frame}[fragile]{staticmethod} - -{ \Large A method that doesn't get self! } - -\begin{verbatim} -class C(object): - def add(a, b): - return a + b - add = staticmethod(add) ->>> C.add(3,4) -7 ->>> c = C() ->>> c.add(2, 2) -4 -\end{verbatim} -{\Large When you don't need self -- can be used from either an instance or the class itself} - -\vfill -see: \verb|static_method.py| -\end{frame} - -\begin{frame}[fragile]{classmethod} - -{ \Large Method gets the class object, rather than an instance, as the first argument} - -\begin{verbatim} -class C(object): - def __init__(self, x, y): - self.x = x - self.y = y - def a_class_method(klass, y): - print "in a_class_method", klass - return klass( y, y**2 ) - a_class_method = classmethod(a_class_method) -\end{verbatim} -{\Large When you need the class object rather than an instance -- plays well with subclassing} -\vfill -see: \verb|class_method.py| -\end{frame} - -\begin{frame}[fragile]{dict.fromkeys()} - -{ \Large \verb|classmethod| often used for alternate constructors:} - -\begin{verbatim} ->>> d = dict([1,2,3]) -Traceback (most recent call last): - File "", line 1, in -TypeError: cannot convert dictionary update -sequence element #0 to a sequence ->>> d = dict.fromkeys([1,2,3]) ->>> d -{1: None, 2: None, 3: None} -\end{verbatim} - -\end{frame} - -\begin{frame}[fragile]{dict.fromkeys()} - -\begin{verbatim} -class Dict: ... - def fromkeys(klass, iterable, value=None): - "Emulate dict_fromkeys() in dictobject.c" - d = klass() - for key in iterable: - d[key] = value - return d - fromkeys = classmethod(fromkeys) -\end{verbatim} - -\vfill -{\Large See also datetime.datetime.now(), etc....} - -\vfill -For a low-level look:\\ -\url{http://docs.python.org/howto/descriptor.html} - -\end{frame} - -\begin{frame}[fragile]{LAB} - -{\Large Write a simple ``Circle'' class:} - -\vfill -\begin{verbatim} -In [13]: c = Circle(radius=3) -In [15]: c.diameter -Out[15]: 6 -In [16]: c.diameter = 8 -In [17]: c.radius -Out[17]: 4.0 -In [18]: c.area -Out[18]: 50.26548245743669 -\end{verbatim} -Use properties so you can keep the radius and diameter in sync, and the area computed on the fly. - -\vfill -Extra Credit: use a class method to make an alternate constructor that takes the diameter instead. -\vfill -{\large \verb|code/circle.py| and \verb|code/test_circle1.py|} -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning Talk: } - -\vfill -{\Large Luke Cypret} - -\vfill -{\Large Blane Moore} - -\vfill - -\end{frame} - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Special Attributes} - -\begin{frame}[fragile]{``magic'' methods} - -{\Large Python's Duck typing:} - -\vfill -{\Large Defining special (or magic) methods in your classes is how you make -your class act like standard classes} - -\end{frame} - -\begin{frame}[fragile]{special methods} - -{\Large We've seen at least one:} - -\vfill -{\Large \verb|__init__|} - -\vfill -{\Large It's all in the double underscores...} - -\vfill -{\Large Pronounced ``dunder'' (or ``under-under'') } - -\vfill -{\Large try: \verb|dir(2)| or \verb|dir(list)| } - -\end{frame} - -\begin{frame}[fragile]{special methods} - -{\Large Emulating Numeric types} - -\begin{verbatim} -object.__add__(self, other) -object.__sub__(self, other) -object.__mul__(self, other) -object.__floordiv__(self, other) -object.__mod__(self, other) -object.__divmod__(self, other) -object.__pow__(self, other[, modulo]) -object.__lshift__(self, other) -object.__rshift__(self, other) -object.__and__(self, other) -object.__xor__(self, other) -object.__or__(self, other)¶ -\end{verbatim} - -\end{frame} - -\begin{frame}[fragile]{special methods} - -{\Large Emulating container types:} - -\begin{verbatim} -object.__len__(self) -object.__getitem__(self, key) -object.__setitem__(self, key, value) -object.__delitem__(self, key) -object.__iter__(self) -object.__reversed__(self) -object.__contains__(self, item) -object.__getslice__(self, i, j) -object.__setslice__(self, i, j, sequence) -object.__delslice__(self, i, j) -\end{verbatim} - -\end{frame} - -\begin{frame}[fragile]{special methods} - -{\Large Example -- to define addition:} - -\begin{verbatim} -def __add__(self, v): - """ - redefine + as element-wise vector sum - """ - assert len(self) == len(v) - return vector([x1 + x2 for x1, x2 in zip(self, v)]) -\end{verbatim} - -( from a nice complete example in \verb|code/vector.py| ) - -\end{frame} - - -\begin{frame}[fragile]{special methods} - -\vfill -{\Large You only need to define the ones that are going to get used} - -\vfill -{\Large But you probably want to define at least these:} - -\vfill -\verb|object.__str__|: Called by the str() built-in function and by the print statement to compute the “informal” string representation of an object. - -\vfill -\verb|object.__repr__|: Called by the repr() built-in function and by string conversions (reverse quotes) to compute the “official” string representation of an object. - -\vfill -(ideally: \verb|eval( repr(something) ) == something| ) - -\end{frame} - -\begin{frame}[fragile]{special methods} - -\vfill -{\Large When you want your class to act like a "standard" class in some way:} - -\vfill -{\Large Look up the magic methods you need and define them} - -\vfill -\url{http://docs.python.org/reference/datamodel.html#special-method-names} - -\vfill -\url{http://www.rafekettler.com/magicmethods.html} -\end{frame} - -\begin{frame}[fragile]{LAB} - -{\Large Extend your ``Circle'' class:} - -\vfill -{\large Add \verb|__str__| and \verb|__repr__| methods } - -\vfill -{\large Write an \verb|__add__| method so you can add two circles } - -(and multiply by a number....) -\begin{verbatim} -In [22]: c1 = Circle(3) -In [23]: c2 = Circle(4) -In [24]: c3 = c1+c2 -In [25]: c3.radius -Out[25]: 7 -In [26]: c1*3 -Out[26]: Circle(9) -\end{verbatim} -{\large If you have time: compare them... (\verb|c1 > c2|, etc)} - -\vfill -{\large \verb|code/circle.py| and \verb|code/test_circle2.py|} -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talk} - -\vfill -{\LARGE Lightning Talk: } - -\vfill -{\Large Brent Parrish} - - -\vfill - -\end{frame} - - -\section{Iterators / Generators} - -% --------------------------------------------- -\begin{frame}[fragile]{Iterators} - -{\Large Iterators are one of the main reasons Python code is so readable:} - -\begin{verbatim} -for x in just_about_anything: - do_stuff(x) -\end{verbatim} - -{\Large you can loop through anything that satisfies the iterator protocol} - -\vfill -\url{http://docs.python.org/library/stdtypes.html#iterator-types} -\end{frame} - -\begin{frame}[fragile]{Iterator Protocol} - -{\Large An iterator must have the following methods:} - -\begin{verbatim} -iterator.__iter__() -\end{verbatim} - -Return the iterator object itself. This is required to allow both containers -and iterators to be used with the for and in statements. - -\begin{verbatim} -iterator.next() -\end{verbatim} - -Return the next item from the container. If there are no further items, -raise the StopIteration exception. - -\end{frame} - - -\begin{frame}[fragile]{Example Iterator} - -{\Large A simple version of \verb|xrange()|} - -\begin{verbatim} -class IterateMe_1(object): - def __init__(self, stop=5): - self.current = 0 - self.stop = stop - def __iter__(self): - return self - def next(self): - if self.current < self.stop: - self.current += 1 - return self.current - else: - raise StopIteration -\end{verbatim} - -\end{frame} - -%------------------------------ -\begin{frame}[fragile]{itertools} - -{\Large \verb|itertools| is a collection of utilities that make it easy to -build an iterator that iterates over sequences in various common ways} - -\begin{verbatim} - -\end{verbatim} - -\url{http://docs.python.org/library/itertools.html} - -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{LAB} - -\begin{itemize} - \item Extend (\verb|iterator_1.py|) to be more like \verb|xrange()| -- - add three input parameters: \verb|iterator_2(start, stop, step=1)| - \item See what happens if you break out in the middle of the loop: -\begin{verbatim} - it = IterateMe_2(2, 20, 2) - for i in it: - if i > 10: break - print i -\end{verbatim} -And then pick up again: -\begin{verbatim} - for i in it: - print i -\end{verbatim} - \item Does \verb|xrange()| behave the same?\\ - -- make yours match \verb|xrange()|. -\end{itemize} -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{generators} - -\Large{Generators give you the iterator immediately: -no access to the underlying data ... if it even exists} - -\vfill -{\bf Conceptually:} - -iterators are about various ways to loop over data, - -generators generate the data on the fly - -\vfill -{\bf Practically:} - -You can use either either way (and a generator is one type of iterator) - -Generators do some of the book-keeping for you. - -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{yield} - -\Large{\verb|yield| is a way to make a quickie generator with a function:} - -\begin{verbatim} -def a_generator_function(params): - some_stuff - yield(something) -\end{verbatim} - -\vfill -\Large{ Generator functions "yield" a value, rather than returning it } - -\vfill -\Large{ State is preserved in between yields } - -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{yield} - -\Large{A function with \verb|yield| in it is a ``factory'' for a generator} - -\vfill -\Large{Each time you call it, you get a new generator:} - -\vfill -\begin{verbatim} -gen_a = a_generator() -gen_b = a_generator() -\end{verbatim} - -\vfill -\Large{ Each instance keeps its own state. } - -\vfill -\Large{ Really just a shorthand for an iterator class that does the book keeping for you.} - -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{yield} - -\Large{An example: like \verb|xrange()|} - -\begin{verbatim} -def y_xrange(start, stop, step=1): - i = start - while i < stop: - yield i - i += step -\end{verbatim} - -\vfill -{\Large Real World Example: \verb|FloatCanvas|} -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{yield} - -{\Large Note:} - -\begin{verbatim} -In [164]: gen = y_xrange(2,6) - -In [165]: type(gen) -Out[165]: generator - -In [166]: dir(gen) -Out[166]: -... - '__iter__', -... - 'next', -\end{verbatim} -{\Large So the generator {\bf is} an iterator} -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{yield} - -{\Large A generator function can also be a method in a class} - -\vfill -{\Large More about iterators and generators:} - -\vfill -\url{http://www.learningpython.com/2009/02/23/iterators-iterables-and-generators-oh-my/} - -\vfill -\verb|yield_example.py| -\end{frame} - -%%------------------------------- -\begin{frame}[fragile]{generator comprehension} - -{\Large another way to make a generator:} - -\begin{verbatim} ->>> [x * 2 for x in [1, 2, 3]] -[2, 4, 6] ->>> (x * 2 for x in [1, 2, 3]) - at 0x10911bf50> ->>> for n in (x * 2 for x in [1, 2, 3]): -... print n -... 2 4 6 -\end{verbatim} - -\vfill -More interesting if [1, 2, 3] is also a generator - -\end{frame} - - -%%------------------------------- -\begin{frame}[fragile]{LAB} - -\vfill -{\LARGE Generator lab:} - -\vfill -{\Large Write a few generators:} -\begin{itemize} - \item Sum of integers - \item Doubler - \item Fibonacci sequence - \item Prime numbers -\end{itemize} - -\vfill -{\Large \verb|code/generatorLAB.html|} - -{\Large \verb|code/test_generator.py|} - -\end{frame} - - - -%------------------------------- -\begin{frame}[fragile]{Homework} - -\vfill -{\Large Finish the labs} - -\vfill -{\LARGE Project Proposals!} - -\vfill -{\Large You should have a good start on your project by the end of this week} - -\vfill -{\Large Remember: no class next week!} - -\vfill - -\end{frame} - - -\end{document} - - diff --git a/slides_sources/old_versions/week-09/PackagingTimeline.pdf b/slides_sources/old_versions/week-09/PackagingTimeline.pdf deleted file mode 100644 index cec04322..00000000 Binary files a/slides_sources/old_versions/week-09/PackagingTimeline.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-09/code/capitalize/capitalize/__init__.py b/slides_sources/old_versions/week-09/code/capitalize/capitalize/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/slides_sources/old_versions/week-09/code/capitalize/capitalize/capital_mod.py b/slides_sources/old_versions/week-09/code/capitalize/capitalize/capital_mod.py deleted file mode 100644 index 352f0874..00000000 --- a/slides_sources/old_versions/week-09/code/capitalize/capitalize/capital_mod.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -""" -A really simple module, just to demonstrate disutils -""" - -def capitalize(infilename, outfilename): - """ - reads the contents of infilename, and writes it to outfilename, but with - every word capitalized - - note: very primitive -- it will mess some files up! - - this is called by the capitalize script - """ - infile = open(infilename, 'U') - outfile = open(outfilename, 'w') - - for line in infile: - outfile.write( " ".join( [word.capitalize() for word in line.split() ] ) ) - outfile.write("\n") - - return None \ No newline at end of file diff --git a/slides_sources/old_versions/week-09/code/capitalize/scripts/cap_script.py b/slides_sources/old_versions/week-09/code/capitalize/scripts/cap_script.py deleted file mode 100755 index 08f999e3..00000000 --- a/slides_sources/old_versions/week-09/code/capitalize/scripts/cap_script.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python - -""" -A really simple script just to demonstrate disutils -""" - -import sys, os -from capitalize import capital_mod - - -if __name__ == "__main__": - try: - infilename = sys.argv[1] - except IndexError: - print "you need to pass in a file to process" - - root, ext = os.path.splitext(infilename) - outfilename = root + "_cap" + ext - - # do the real work: - print "Capitalizing: %s and storing it in %s"%(infilename, outfilename) - capital_mod.capitalize(infilename, outfilename) - - print "I'm done" - \ No newline at end of file diff --git a/slides_sources/old_versions/week-09/code/capitalize/setup.py b/slides_sources/old_versions/week-09/code/capitalize/setup.py deleted file mode 100755 index d7acd8eb..00000000 --- a/slides_sources/old_versions/week-09/code/capitalize/setup.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -""" -This is about as simple a setup.py as you can have - -It installs the capitalize module and script - -""" - -# classic distutils -#from distutils.core import setup - -## uncomment to support "develop" mode -from setuptools import setup - -setup( - name='Capitalize', - version='0.1.0', - author='Chris Barker', - py_modules=['capitalize/capital_mod',], - scripts=['scripts/cap_script.py',], - description='Not very useful capitalizing module and script', -) - diff --git a/slides_sources/old_versions/week-09/code/capitalize/test/test_text_file.txt b/slides_sources/old_versions/week-09/code/capitalize/test/test_text_file.txt deleted file mode 100644 index a64b50f7..00000000 --- a/slides_sources/old_versions/week-09/code/capitalize/test/test_text_file.txt +++ /dev/null @@ -1,7 +0,0 @@ -This is a really simple Text file. -It is here so that I can test the capitalize script. - -And that's only there to try out distutils. - -So there. - \ No newline at end of file diff --git a/slides_sources/old_versions/week-09/code/context_manager/timer_context.html b/slides_sources/old_versions/week-09/code/context_manager/timer_context.html deleted file mode 100644 index 93c4a5d9..00000000 --- a/slides_sources/old_versions/week-09/code/context_manager/timer_context.html +++ /dev/null @@ -1,387 +0,0 @@ - - - - - - -A context manager as a simple timer - - - -
        -

        A context manager as a simple timer

        - -

        See if you can write a context manger that will time some code.

        -

        When using it, you can do:

        -
        -with timer:
        -    this_is_some_code_to_run()
        -    how_long_might_it_take
        -
        -

        and you'll get something like:

        -
        -this code took 0.12 seconds
        -
        -
        -

        NOTE:

        -

        you can do simple timing with the time module. Without a context, you'd do:

        -
        -import time
        -
        -start_time = time.clock()
        -
        -run_some_code_here
        -
        -run_time = time.clock - start_time
        -print "this code took %f seconds"%run_time)
        -
        -
        -
        But isn't::
        -
        with Timer():
        -
        -

        easier?

        -
        -
        -

        NOTE2:

        -

        The context manager's __exit__() method is called with three arguments, the exception details (type, value, traceback): the same values returned by sys.exc_info(), which can also be None if no exception occurred).

        -

        If you do'nt want to do anytihng special with exceptions, youc an ignore them, but the __exit__ method msut take something:

        -
        -def __exit__(self, *args)
        -    your_code_that
        -    ignors_exceptions
        -
        -

        will do fine...

        -
        -
        - - diff --git a/slides_sources/old_versions/week-09/code/context_manager/timer_context.py b/slides_sources/old_versions/week-09/code/context_manager/timer_context.py deleted file mode 100755 index 99050ea2..00000000 --- a/slides_sources/old_versions/week-09/code/context_manager/timer_context.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -""" -timer_context - -A context manager that does simpel code timing - -Adapted from: - -http://preshing.com/20110924/timing-your-code-using-pythons-with-statement/ - - -NOTE: this is only good for crude timing -- use the timeit module to do it better. -""" - -import time - -class Timer(object): - def __enter__(self): - pass - def __exit__(self, *args): - pass - - -if __name__ == "__main__": - - # hard to write proper unit tests for this... - - with Timer() as t: - for i in range(100000): - i = i**20 - - print t.interval - - - - - - - diff --git a/slides_sources/old_versions/week-09/code/context_manager/timer_context.rst b/slides_sources/old_versions/week-09/code/context_manager/timer_context.rst deleted file mode 100644 index e26a64fc..00000000 --- a/slides_sources/old_versions/week-09/code/context_manager/timer_context.rst +++ /dev/null @@ -1,49 +0,0 @@ -A context manager as a simple timer -##################################### - -See if you can write a context manger that will time some code. - -When using it, you can do:: - - with timer: - this_is_some_code_to_run() - how_long_might_it_take - - -and you'll get something like:: - - this code took 0.12 seconds - -NOTE: -------- - -you can do simple timing with the time module. Without a context, you'd do:: - - import time - - start_time = time.clock() - - run_some_code_here - - run_time = time.clock - start_time - print "this code took %f seconds"%run_time) - -But isn't:: - with Timer(): - -easier? - - -NOTE2: -------- - -The context manager's __exit__() method is called with three arguments, the exception details (type, value, traceback): the same values returned by sys.exc_info(), which can also be None if no exception occurred). - -If you do'nt want to do anytihng special with exceptions, youc an ignore them, but the __exit__ method msut take something:: - - def __exit__(self, *args) - your_code_that - ignors_exceptions - - -will do fine... \ No newline at end of file diff --git a/slides_sources/old_versions/week-09/code/context_manager/timer_context_solution.py b/slides_sources/old_versions/week-09/code/context_manager/timer_context_solution.py deleted file mode 100755 index 1aaa8a25..00000000 --- a/slides_sources/old_versions/week-09/code/context_manager/timer_context_solution.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python - -""" -timer_context - -A context manager that does simpel code timing - -Adapted from: - -http://preshing.com/20110924/timing-your-code-using-pythons-with-statement/ - - -NOTE: this is only good for crude timing -- use the timeit module to do it better. -""" - -import time - -class Timer(object): - def __enter__(self): - self.start = time.clock() - return self - - def __exit__(self, *args): - self.end = time.clock() - self.interval = self.end - self.start - print "this code took %f seconds"%self.interval - -if __name__ == "__main__": - - # hard to write proper unit tests for this... - - with Timer() as t: - for i in range(100000): - i = i**20 - - print t.interval - - - - - - - diff --git a/slides_sources/old_versions/week-09/code/decorators/DecoratorDemo.ipynb b/slides_sources/old_versions/week-09/code/decorators/DecoratorDemo.ipynb deleted file mode 100644 index d8487ae2..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/DecoratorDemo.ipynb +++ /dev/null @@ -1,514 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Demonstration of Decorators:\n", - "\n", - " (Adapted from Jon Jacky's Intro to Python class)\n", - "\n", - "### Creating a function in a function...." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def addn(n):\n", - " def adder(i):\n", - " return i + n\n", - " return adder" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "NOTE: you oculd use lambda for something as simple as this..." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "add2 = addn(2)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "add2 (1)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 3, - "text": [ - "3" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "add3 = addn(3)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "add3(1)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 5, - "text": [ - "4" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A function that takes a function as an argument, and returns a function can be a decorator.\n", - "\n", - "It usually creates a function inside its scope..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Pass a function as an argument, use that to define the function you return.\n", - "\n", - "(first a couple functions to use...)" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def odd(i):\n", - " return i%2\n", - "def even(i):\n", - " return not odd(i)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 6 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And write a wrapper for them...." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def sieve(f):\n", - " def siever(s):\n", - " return [x for x in s if f(x)]\n", - " return siever" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 8 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make a couple of sieves:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "oddsieve = sieve(odd)\n", - "evensieve = sieve(even)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 9 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And try them out:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "s = range(10)\n", - "s" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 10, - "text": [ - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" - ] - } - ], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "oddsieve(s)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 11, - "text": [ - "[1, 3, 5, 7, 9]" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "evensieve(s)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 12, - "text": [ - "[0, 2, 4, 6, 8]" - ] - } - ], - "prompt_number": 12 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The decorator operator @ abbreviates the preceding pattern\n", - "\n", - "`@f\n", - " def g\n", - "`\n", - "means\n", - "\n", - "`g = f(g)`" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@sieve\n", - "def osieve(i):\n", - " return i % 2\n", - "\n", - "@sieve\n", - "def esieve(i):\n", - " return not (i % 2)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 13 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "osieve(s)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 16, - "text": [ - "[1, 3, 5, 7, 9]" - ] - } - ], - "prompt_number": 16 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "esieve(s)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 17, - "text": [ - "[0, 2, 4, 6, 8]" - ] - } - ], - "prompt_number": 17 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A callable class can be used as a function, so \n", - "you can also use a class as a decorator\n", - "\n", - "(classes and objects are callable (via `__init__` and `__call__`))" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "class Memoize:\n", - " \"\"\"\n", - " memoize decorator from avinash.vora\n", - " http://avinashv.net/2008/04/python-decorators-syntactic-sugar/\n", - " \"\"\"\n", - " def __init__(self, function): # runs when memoize class is called\n", - " self.function = function\n", - " self.memoized = {}\n", - "\n", - " def __call__(self, *args): # runs when memoize instance is called\n", - " try:\n", - " return self.memoized[args]\n", - " except KeyError:\n", - " self.memoized[args] = self.function(*args)\n", - " return self.memoized[args]" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 18 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To use it -- the nifty decorator syntax:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@Memoize # same effect as sum2x = memoize(sum2x)\n", - "def sum2x(n):\n", - " return sum(2 * i for i in xrange(n)) # takes time when n > 10 million" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 19 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "call it:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "sum2x(10)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 20, - "text": [ - "90" - ] - } - ], - "prompt_number": 20 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "sum2x(10)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 21, - "text": [ - "90" - ] - } - ], - "prompt_number": 21 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "But slow if you call it with a big number:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import time\n", - "start = time.clock()\n", - "sum2x(10000000)\n", - "print \"it took %f seconds to run\"%(time.clock() - start)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "it took 0.968653 seconds to run\n" - ] - } - ], - "prompt_number": 22 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "But the second time..." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import time\n", - "start = time.clock()\n", - "sum2x(10000000)\n", - "print \"it took %f seconds to run\"%(time.clock() - start)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "it took 0.000184 seconds to run\n" - ] - } - ], - "prompt_number": 23 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Quiz time: what type of object is sum2x ?" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "repr(sum2x)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 24, - "text": [ - "'<__main__.Memoize instance at 0x102f80488>'" - ] - } - ], - "prompt_number": 24 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/slides_sources/old_versions/week-09/code/decorators/DecoratorDemo.py b/slides_sources/old_versions/week-09/code/decorators/DecoratorDemo.py deleted file mode 100644 index 5857c155..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/DecoratorDemo.py +++ /dev/null @@ -1,203 +0,0 @@ -# -*- coding: utf-8 -*- -# 3.0 - -# - -# ## Demonstration of Decorators: -# -# (Adapted from Jon Jacky's Intro to Python class) -# -# ### Creating a function in a function.... - -# - -def addn(n): - def adder(i): - return i + n - return adder - -# - -# NOTE: you oculd use lambda for something as simple as this... - -# - -add2 = addn(2) - -# - -add2 (1) - -# - -add3 = addn(3) - -# - -add3(1) - -# - -# A function that takes a function as an argument, and returns a function can be a decorator. -# -# It usually creates a function inside its scope... - -# - -# Pass a function as an argument, use that to define the function you return. -# -# (first a couple functions to use...) - -# - -def odd(i): - return i%2 -def even(i): - return not odd(i) - -# - -# And write a wrapper for them.... - -# - -def sieve(f): - def siever(s): - return [x for x in s if f(x)] - return siever - -# - -# Make a couple of sieves: - -# - -oddsieve = sieve(odd) -evensieve = sieve(even) - -# - -# And try them out: - -# - -s = range(10) -s - -# - -oddsieve(s) - -# - -evensieve(s) - -# - -# The decorator operator @ abbreviates the preceding pattern -# -# `@f -# def g -# ` -# means -# -# `g = f(g)` - -# - -@sieve -def osieve(i): - return i % 2 - -@sieve -def esieve(i): - return not (i % 2) - -# - -osieve(s) - -# - -esieve(s) - -# - -# A callable class can be used as a function, so -# you can also use a class as a decorator -# -# (classes and objects are callable (via `__init__` and `__call__`)) - -# - -class Memoize: - """ - memoize decorator from avinash.vora - http://avinashv.net/2008/04/python-decorators-syntactic-sugar/ - """ - def __init__(self, function): # runs when memoize class is called - self.function = function - self.memoized = {} - - def __call__(self, *args): # runs when memoize instance is called - try: - return self.memoized[args] - except KeyError: - self.memoized[args] = self.function(*args) - return self.memoized[args] - -# - -# To use it -- the nifty decorator syntax: - -# - -@Memoize # same effect as sum2x = memoize(sum2x) -def sum2x(n): - return sum(2 * i for i in xrange(n)) # takes time when n > 10 million - -# - -# call it: - -# - -sum2x(10) - -# - -sum2x(10) - -# - -# But slow if you call it with a big number: - -# - -import time -start = time.clock() -sum2x(10000000) -print "it took %f seconds to run"%(time.clock() - start) - -# - -# But the second time... - -# - -import time -start = time.clock() -sum2x(10000000) -print "it took %f seconds to run"%(time.clock() - start) - -# - -# Quiz time: what type of object is sum2x ? - -# - -repr(sum2x) - -# - - diff --git a/slides_sources/old_versions/week-09/code/decorators/basic_math.ipynb b/slides_sources/old_versions/week-09/code/decorators/basic_math.ipynb deleted file mode 100644 index 796a18d5..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/basic_math.ipynb +++ /dev/null @@ -1,307 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def add(a,b):\n", - " return a+b" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "add(3,4)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 2, - "text": [ - "7" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What if we want to log when that function is called?" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def logged_add(a, b):\n", - " print '### %s(%r, %r)' % ('add', a, b)\n", - " result = add(a, b)\n", - " print '### %s(%r, %r) --> %r' % ('add', a, b, result)\n", - " return result" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "could change all calls to this -- blech!\n", - "\n", - "so instead write a wrapper:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def logged(func):\n", - " def wrapper(a, b):\n", - " print '### %s(%r, %r)' % (func.func_name, a, b)\n", - " result = func(a, b)\n", - " print '### %s(%r, %r) --> %r' % (func.func_name, a, b, result)\n", - " return result\n", - " return wrapper" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 5 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "re-define add..." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "add = logged(add)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "add(3,4)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "### add(3, 4)\n", - "### add(3, 4) --> 7\n" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 6, - "text": [ - "7" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And use it for other functions, too:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def subtract(a, b):\n", - " \"\"\"subtract() subtracts two things\"\"\"\n", - " return a - b\n", - "subtract = logged(subtract)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "subtract(7,4)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "### subtract(7, 4)\n", - "### subtract(7, 4) --> 3\n" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 8, - "text": [ - "3" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Make it more general -- to take any number of arguments:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def logged(func):\n", - " def wrapper(*args):\n", - " print '### %s(%s)' % (func.func_name, args)\n", - " result = func(*args)\n", - " print '### %s(%s) --> %r' % (func.func_name, args, result)\n", - " return result\n", - " return wrapper" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 9 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A function with one argument:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def even(a):\n", - " \"\"\"even() returns True if the value is even\"\"\"\n", - " return a % 2 == 0\n", - "even = logged(even)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "even(3)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "### even((3,))\n", - "### even((3,)) --> False\n" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 11, - "text": [ - "False" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "even(4)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "### even((4,))\n", - "### even((4,)) --> True\n" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 12, - "text": [ - "True" - ] - } - ], - "prompt_number": 12 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 12 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/slides_sources/old_versions/week-09/code/decorators/basic_math.py b/slides_sources/old_versions/week-09/code/decorators/basic_math.py deleted file mode 100644 index 567440d3..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/basic_math.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- coding: utf-8 -*- -# 3.0 - -# - -def add(a,b): - return a+b - -# - -add(3,4) - -# - -# What if we want to log when that function is called? - -# - -def logged_add(a, b): - print '### %s(%r, %r)' % ('add', a, b) - result = add(a, b) - print '### %s(%r, %r) --> %r' % ('add', a, b, result) - return result - -# - -# could change all calls to this -- blech! -# -# so instead write a wrapper: - -# - -def logged(func): - def wrapper(a, b): - print '### %s(%r, %r)' % (func.func_name, a, b) - result = func(a, b) - print '### %s(%r, %r) --> %r' % (func.func_name, a, b, result) - return result - return wrapper - -# - -# re-define add... - -# - -add = logged(add) - -# - -add(3,4) - -# - -# And use it for other functions, too: - -# - -def subtract(a, b): - """subtract() subtracts two things""" - return a - b -subtract = logged(subtract) - -# - -subtract(7,4) - -# - -# Make it more general -- to take any number of arguments: - -# - -def logged(func): - def wrapper(*args): - print '### %s(%s)' % (func.func_name, args) - result = func(*args) - print '### %s(%s) --> %r' % (func.func_name, args, result) - return result - return wrapper - -# - -# A function with one argument: - -# - -def even(a): - """even() returns True if the value is even""" - return a % 2 == 0 -even = logged(even) - -# - -even(3) - -# - -even(4) - -# - -# Wouldn't it be nice to have a cleaner syntax that this??? - diff --git a/slides_sources/old_versions/week-09/code/decorators/circle_properties.py b/slides_sources/old_versions/week-09/code/decorators/circle_properties.py deleted file mode 100644 index 3875d37d..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/circle_properties.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -""" -circle class -- - -basic skeleton: fill in with properties.. - -Write a Circle class with decorator syntax for properties: - instantiate with a radius: c = Circle(4) - -Use a property for the diameter: get and settable: - d = c.diameter - c.diameter = 5 - -use a property for the area: only gettable - a = c.area - a.area = 5 => AttributeError - -add methods so that str(circle) and repr(circle) - produce something reasonable. - -extra credit: make it so you can add two circles: - ->>> Circle(2) + Circle(3) -Circle(5.000000) - - -see test_circle_properties.py for requirements. - -""" - -import math - -class Circle(object): - def __init__(self, radius): - self.radius = radius - - # put the rest in here... \ No newline at end of file diff --git a/slides_sources/old_versions/week-09/code/decorators/circle_properties_solution.py b/slides_sources/old_versions/week-09/code/decorators/circle_properties_solution.py deleted file mode 100644 index 2544153b..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/circle_properties_solution.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -""" -Circle class -- my solution to the exercise - -Test code to run it is in test_circle.py -""" - -import math - -class Circle(object): - def __init__(self, radius): - self.radius = radius - - @classmethod - def from_diameter(cls, diameter): - return cls(diameter/2.0) - - @staticmethod - def circumference(radius): - return math.pi * 2 * radius - - @property - def diameter(self): - return self.radius * 2 - @diameter.setter - def diameter(self, value): - self.radius = value / 2.0 - - @property - def area(self): - return self.radius**2 * math.pi - - def __add__(self, other): - return Circle(self.radius + other.radius) - - def __repr__(self): - return "Circle(%f)"%self.radius - - def __str__(self): - return "Circle Object with radius: %f"%self.radius - diff --git a/slides_sources/old_versions/week-09/code/decorators/p_wrapper.py b/slides_sources/old_versions/week-09/code/decorators/p_wrapper.py deleted file mode 100644 index e3e13b76..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/p_wrapper.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Python decorator example - -Simple decorator that turns any function that returns a string -into one that returns that string wrapped in the html

        tag: - -@p_wrapper -def func(): - " simplest example possible" - return "this is the returned string" - ->> func() - -"

        this is the returned string

        " - -""" - -# the simple decorator - -def p_wrapper(func): - ## put decorator here - pass - - - -""" - -Fancier decorator using a class: - -This lets you make a decorator with some custom input - -the argument to the __init__ sets what tag you want, which creates a custom decorator. - -the __call__ method is the decorator itself. - -""" - -class tag_wrapper(object): - def __init__(self, tag='p' ): - """ - inititilze the decorator class with the tag you want - """ - pass - def __call__(self, func, *args, **kwargs): - """ - The actual decorator function. - """ - pass - # return a_function... - diff --git a/slides_sources/old_versions/week-09/code/decorators/p_wrapper_solution.py b/slides_sources/old_versions/week-09/code/decorators/p_wrapper_solution.py deleted file mode 100644 index 8943860e..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/p_wrapper_solution.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Python decorator example - -Simple decorator that turns any function that returns a string -into one that returns that string wrapped in the html

        tag: - -@p_wrapper -def func(): - " simplest example possible" - return "this is the returned string" - -func() - -""" - -# the simple decorator - -def p_wrapper(func): - def function(*args, **kwargs): - result = func(*args, **kwargs) - return "

        " + result + "

        " - return function - -""" - -Fancier decorator using a class: - -this lets you make a decorator with some custom input -the argument to the __init__ sets what tag you want -this creates a custom decorator -the __call__ method is the decorator itself. - -""" - -class tag_wrapper(object): - def __init__(self, tag='p' ): - """ - inititilze the decorator class with the tag you want - """ - self.open_tag = "<%s> "%tag - self.close_tag = " "%tag - - def __call__(self, func, *args, **kwargs): - """ - The actual decorator function. - - using lambda - 'cause why not? - """ - return lambda *args, **kwargs: self.open_tag + func(*args, **kwargs) + self.close_tag - diff --git a/slides_sources/old_versions/week-09/code/decorators/properties_dec_example.py b/slides_sources/old_versions/week-09/code/decorators/properties_dec_example.py deleted file mode 100644 index 68ea23ff..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/properties_dec_example.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -""" -example code for properties using the decorator syntax -""" - -class C(object): - _x = None - @property - def x(self): - return self._x - @x.setter - def x(self, value): - self._x = value - @x.deleter - def x(self): - del (self._x) - -if __name__ == "__main__": - c = C() - c.x = 5 - print c.x - c.x = 7 - print c.x - del c.x - print c.x diff --git a/slides_sources/old_versions/week-09/code/decorators/test_circle_properties.py b/slides_sources/old_versions/week-09/code/decorators/test_circle_properties.py deleted file mode 100644 index b36b83e6..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/test_circle_properties.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python - -import math - -import pytest - -""" -code that tests the circle class defined in circle.py - -designed to be run with py.test - -(but most will run with nose, too) - -""" - -from circle_properties import Circle -#from circle_properties_solution import Circle - - -def test_basic(): - c = Circle(4) - print "the radius:", c.radius - print "the diameter:", c.diameter - print "the area:", c.area - print "the repr():", repr(c) - print "the str():", str(c) - assert c.radius == 4 - assert c.diameter == 8 - assert round(c.area, 5) == 50.26548 - - -def test_change_r(): - """ - testing changing the radius - """ - c = Circle(4) - - #"setting the radius to 2:" - c.radius = 2 - assert c.radius == 2 - assert c.diameter == 4 - assert round(c.area, 5) == 12.56637 - -def test_change_d(): - """ - testing changing the diameter - """ - c = Circle(4) - - c.diameter = 4 - assert c.radius == 2 - assert c.diameter == 4 - assert round(c.area, 5) == 12.56637 - -## testing properties errors -## These require pytest - -def test_delete(): - # trying to delete the diameter - c = Circle(4) - with pytest.raises(AttributeError): - del c.diameter - -def test_set_area(): - # trying to set the area - c = Circle(4) - with pytest.raises(AttributeError): - c.area = 12 - -def test_add_circles(): - """ - testing the addition of two circle objects - """ - c1 = Circle(2) - c2 = Circle(4) - c3 = c1 + c2 - assert c3.radius == 6 - assert c3.diameter == 12 - -def test_repr(): - c = Circle(5) - assert repr(c) == 'Circle(5.000000)' - -def test_str(): - c = Circle(5) - print str(c) - assert str(c) == 'Circle Object with radius: 5.000000' - -def test_from_diameter(): - c = Circle.from_diameter(6.0) - assert c.radius == 3.0 - -def test_circumference(): - c = Circle.circumference(3.0) - assert c == math.pi * 3.0 * 2 diff --git a/slides_sources/old_versions/week-09/code/decorators/test_p_wrapper.py b/slides_sources/old_versions/week-09/code/decorators/test_p_wrapper.py deleted file mode 100644 index 1cf75c7b..00000000 --- a/slides_sources/old_versions/week-09/code/decorators/test_p_wrapper.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -Python decorator example - -simple decorator that turns any function that returns a string -into one that returns that string wrapped in the html

        tag: - -@p_wrapper -def func(): - " simplest example possible" - return "this is the returned string" - ->> func() - -"

        this is the returned string

        " - -Advanced: - -Try using a class to make a decorator that will wrap a -specified tag around a function that returns a string -- i.e: - -@tag_wrapper('h1') -def func2(x, y=4, z=2): - return "the sum of %s and %s and %s is %s"%(x, y, z, x+y+z) - ->>> print func2(3,4) -

        the sum of 3 and 4 and 2 is 9

        - - -""" - -from p_wrapper import p_wrapper, tag_wrapper -#from p_wrapper_solution import p_wrapper, tag_wrapper - - -def test_simple_func(): - def func(): - " simplest example possible" - return "this is the returned string" - - print "the raw version" - print func() - - assert func() == "this is the returned string" - - # now add the decorator: - @p_wrapper - def func(): - " simplest example possible" - return "this is the returned string" - - print "the decorated version" - print func() - - assert func() == "

        this is the returned string

        " - -def test_more_complex_function(): - # # try it with another function - - @p_wrapper - def func2(x,y): - return "the sum of %s and %s is %s"%(x, y, x+y) - - # call it: - print func2(3,4) - - assert func2(3,4) == "

        the sum of 3 and 4 is 7

        " - -def test_func_with_keywords(): - # # and one with keyword arguments - - @p_wrapper - def func2(x, y=4, z=2): - return "the sum of %s and %s and %s is %s"%(x, y, z, x+y+z) - - # call it: - print func2(3) - print func2(3, 5) - print func2(3, 5, 7) - - assert func2(3,5,7) == "

        the sum of 3 and 5 and 7 is 15

        " - -## testing the class version -def test_class_decorator(): - - @tag_wrapper('h1') - def func2(x, y=4, z=2): - return "the sum of %s and %s and %s is %s"%(x, y, z, x+y+z) - - print func2(3,4) - - assert func2(3,4) == "

        the sum of 3 and 4 and 2 is 9

        " - -def test_class_decorator_div(): - - @tag_wrapper('div') - def func2(x, y=4, z=2): - return "the sum of %s and %s and %s is %s"%(x, y, z, x+y+z) - - print func2(5,6,7) - - assert func2(5,6,7) == "
        the sum of 5 and 6 and 7 is 18
        " - diff --git a/slides_sources/old_versions/week-09/packaging1.pdf b/slides_sources/old_versions/week-09/packaging1.pdf deleted file mode 100644 index 0021ff2d..00000000 Binary files a/slides_sources/old_versions/week-09/packaging1.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-09/presentation-week-09.pdf b/slides_sources/old_versions/week-09/presentation-week-09.pdf deleted file mode 100644 index ed11a839..00000000 Binary files a/slides_sources/old_versions/week-09/presentation-week-09.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-09/presentation-week-09.tex b/slides_sources/old_versions/week-09/presentation-week-09.tex deleted file mode 100644 index 38012294..00000000 --- a/slides_sources/old_versions/week-09/presentation-week-09.tex +++ /dev/null @@ -1,1165 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Intro to Python: Week 9]{Introduction to Python\\ -Decorators, Context Managers, \\ -Packages and Packaging} -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{December 3, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - - -\section{Review/Questions} - -% --------------------------------------------- -\begin{frame}{Review of Previous Class} - -\begin{itemize} - \item Magic methods - \item Iterators - \item Generators - \item (wxPython) -\end{itemize} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning talks today:} - -\vfill -{\Large - -\vfill - Harlan AuBuchon -\vfill - Luke Cypret -\vfill - Brian Schmitz -\vfill - -} -\vfill - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Review} - - \vfill - {\Large Questions about labs? } - - \vfill - {\Large My Solutions? } - - \vfill - -\end{frame} - -\begin{frame}[fragile]{A diversion...} - -\Large{A number of you are already using \verb|iPython|} - -\vfill -\Large{It's a very useful tool} - -\vfill -\Large{And the \verb|iPython| notebook is even cooler .. paticularly for in-class demos.} - -\vfill -\Large{So I'll use it some today:} - -\vfill -\url{http://ipython.org/ipython-doc/dev/interactive/notebook.html} - - -\end{frame} - - -%######################## -\section{Decorators} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorators} - -{\LARGE Decorators are wrappers around functions} - -\vfill -{\LARGE They let you add code before and after the execution of a function} - -\vfill -{\LARGE Creating a custom version of that function} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorators} - -{\LARGE Syntax:} - -\vfill -\begin{verbatim} -@logged -def add(a, b): - """add() adds things""" - return a + b -\end{verbatim} - -\vfill -{\Large Demo and Motivation: \\ -\verb|code/decorators/basic_math.py [ipnb]| } - -\vfill -PEP: \url{http://www.python.org/dev/peps/pep-0318/} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorators} - -{\LARGE \verb|@| decorator operator is an abbreviation:} - -{\large -\vfill -\begin{verbatim} -@f -def g: - pass -\end{verbatim} - -\vfill -same as - -\vfill -\begin{verbatim} -def g: - pass -g = f(g) -\end{verbatim} -} - -\vfill -{\Large ``Syntactic Sugar'' -- but really quite nice} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorators} - -{\LARGE demo: - -\vfill -\begin{verbatim} -decorator.py -\end{verbatim} - -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorator examples} - -{\LARGE Examples from the stdlib:} - -\vfill -{\Large Does this structure:} - -\vfill -\begin{verbatim} -def g: - pass -g = f(g) -\end{verbatim} - -\vfill - -{\Large look familiar from last class?} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorator examples} - -{\LARGE \verb|staticmethod()|} - -\vfill -\begin{verbatim} -class C(object): - def add(a, b): - return a + b - add = staticmethod(add) -\end{verbatim} - -\vfill - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorator examples} - -{\LARGE \verb|staticmethod()|} - -\vfill -{\Large Decorator form:} -\begin{verbatim} -class C(object): - @staticmethod - def add(a, b): - return a + b -\end{verbatim} - -\vfill - -{\LARGE ( and \verb|classmethod| )} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{examples} - -{\LARGE \verb|property()|} - -\vfill -\begin{verbatim} -class C(object): - def __init__(self): - self._x = None - def getx(self): - return self._x - def setx(self, value): - self._x = value - def delx(self): - del self._x - x = property(getx, setx, delx, - "I'm the 'x' property.") -\end{verbatim} - -\vfill -{\large becomes...} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Decorator examples} - -\begin{verbatim} -class C(object): - def __init__(self): - self._x = None - @property - def x(self): - return self._x - @x.setter - def x(self, value): - self._x = value - @x.deleter - def x(self): - del self._x -\end{verbatim} - -\vfill -{\large Puts the info close to where it is used} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{examples} - -{\LARGE CherryPy} - -\vfill -\begin{verbatim} -import cherrypy -class HelloWorld(object): - @cherrypy.expose - def index(self): - return "Hello World!" -cherrypy.quickstart(HelloWorld()) -\end{verbatim} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{examples} - -{\LARGE Pyramid} - -\vfill -\begin{verbatim} - -@template -def A_view_function(request) - ..... -@json -def A_view_function(request) - ...... - - -\end{verbatim} - -so you don't need to think about what your view is returning... - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{decorators...} - -{\Large For this class:} - -\vfill -{\Large Mostly want to you to know how to use decorators that someone else has written} - -\vfill -{\Large Have a basic idea what they do when you do use them} - -\vfill -{\Large But writing a couple will help you ``get'' it, and help cement your Python knowledge...} - - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Writing Decorators} - -{\LARGE So how to you write one?} - -\vfill -{\Large -demo in iPython notebook - -\vfill -\begin{verbatim} -code\decorators\DecoratorDemo.py -\end{verbatim} -} - -\vfill -{\large For more detail: (and talks about closures...):}\\ - -\url{http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{LAB} - -\begin{itemize} - \item Re-write the properties from last week's \verb|Circle| class - to use the decorator syntax (see a couple slides back for an example)\\ - (\verb|circle_properties.py| and \verb|test_circle_properties.py|) - \item Write a decorator that can be used to wrap any function that returns a string in a \verb|

        | element -- auto-generation of simple html. - (\verb|p_wrapper.py|) - - \item Try using a class to make a decorator that will wrap a - specified tag around a function that returns a string: - \begin{verbatim} - @tag_wrapper('h1') - def func2(x, y=4, z=2): - return "the sum of %s and %s and %s is %s"%(x, y, z, x+y+z) - >>> print func2(3,4) -

        the sum of 3 and 4 and 2 is 9

        - \end{verbatim} -\end{itemize} - -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -\vfill -{\Large Harlan AuBuchon} - -\vfill -{\Large Luke Cypret} - -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Context Managers} - -%---------------------------------------- -\begin{frame}[fragile]{Context Managers} - -{\LARGE the \verb|with| statement} - -\vfill -{\Large A class with \verb|__enter__()| and \verb|__exit__()| methods.} - -\vfill -{\Large \verb|__enter__()| is run before your block of code} - -\vfill -{\Large \verb|__exit__()| is run after your block of code} - -\vfill -{\Large Can be used to setup/cleanup before and after: open/closing files, db connections, etc} -\end{frame} - -%---------------------------------------- -\begin{frame}[fragile]{Context Managers} - -{\Large ``PEP 343: the \verb|with| statement''} \\ -\hspace{0.2in} -- A.M. Kuchling - -\url{http://docs.python.org/dev/whatsnew/2.6.html#pep-343-the-with-statement} - -\vfill -{\Large ``Understanding Python's \verb|with| statement''} \\ -\hspace{0.2in} -- Fredrik Lundh - -\url{http://effbot.org/zone/python-with-statement.htm} - -\vfill -{\Large ``The Python \verb|with| Statement by Example''} \\ -\hspace{0.2in} -- Jeff Preshing - -\url{http://preshing.com/20110920/the-python-with-statement-by-example} - -\end{frame} - - -%---------------------------------------- -\begin{frame}[fragile]{Context Managers} - -{\Large Use syntax:} - -\begin{verbatim} -with manager as something: - a = block_of_code - use_something_here(something) - ... -\end{verbatim} - -\vfill -{\large -\verb`manager` is the context manager: i.e. has an \verb`__enter__` and \verb`__exit__` method -- if \verb`__enter__` returns an object, it gets assigned to \verb`something` -} - -\vfill -\end{frame} - -%---------------------------------------- -\begin{frame}[fragile]{Context Managers} - -{\Large The file object is also a context manager:} - -\begin{verbatim} -with open(filename) as the_file: - for line in the_file: - work_with(line) - ... - ... -\end{verbatim} - -\vfill - -{\Large In this case, the file will automatically be closed when you leave that block, regardless of errors, etc.} -\vfill - -{\Large Most commonly used context manager -- by far!} - -\end{frame} - -%---------------------------------------- -\begin{frame}[fragile]{Context Managers} - -{\Large You also may hav seen this in some of my unit tests:} - -\begin{verbatim} -with pytest.raises(ZeroDivisionError): - some_test_code_here - 1/0 -\end{verbatim} - -\vfill - -{\Large Context Managers can also catch Exceptions....} -\vfill - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large See if you can write a context manger that will time some code.} - -{\large When using it, you can do:} -\begin{verbatim} - with timer: - this_is_some_code_to_run() - how_long_might_it_take -\end{verbatim} - -{\large and you'll get something like:} - -\begin{verbatim} - this code took 0.12 seconds -\end{verbatim} - -\vfill -{\large See: \verb`context_manager\timer_context.html` (\verb`timer_context.py`) } - -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talk} - -{\LARGE Lightning Talk:} - -\vfill -{\large Brian Schmitz} - -\end{frame} - - -\section{Packages and Packaging} - -% --------------------------------------------- -\begin{frame}[fragile]{Modules and Packages} - -\vfill -{\Large A module is a file with python code in it} - -\vfill -{\Large A package is a directory with an \verb|__init__.py| file in it} - -\vfill -{\Large And usually other modules, packages, etc...} - -\begin{verbatim} -my_package - __init__.py - module_a.py - module_b.py -\end{verbatim} - -\begin{verbatim} -import my_package -\end{verbatim} - -runs \verb|my_package/__init__.py| - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Modules and Packages} - -\vfill -\begin{verbatim} -import sys - -for p in sys.path: - print p - -\end{verbatim} - -\vfill -(demo) -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Installing Python} - -{\Large Linux:} - -Usually part of the system -- just use it - -\vfill -{\Large Windows:} - -\vfill -Use the \url{python.org} version: - -\vfill -System Wide - -\vfill -Can install multiple versions if need be - -\vfill -Third party binaries for it. - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Installing Python} - -{\Large OS-X:} - -Comes with the system, but: -\begin{itemize} - \item Apple has never upgraded within a release - \item There are non-open source components - \item Third party packages may or may not support it - \item Apple does use it -- so don't mess with it. - \item I usually recommend the \url{python.org} version -\end{itemize} -(Also Macports, Fink, Home Brew...) - -\vfill -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Distributions} - -\vfill -{\Large There are also a few ``curated'' distributions:} - -\vfill -{\Large These provide python and a package management system for hard-to-buid packages.} - -\vfill -{\Large Widely used by the scipy community (lots of hard to build stuff that needs to work together...)} - -{\large -\begin{itemize} - \item Anoconda (\url{https://store.continuum.io/cshop/anaconda/}) - \item Canopy (\url{https://www.enthought.com/products/canopy/}) - \item ActivePython (\url{http://www.activestate.com/activepython}) -\end{itemize} -} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Installing Packages} - -{\Large Every Python installation has its own stdlib and \verb|site-packages| folder} - -\vfill -{\Large\verb|site-packages| is the default place for third-party packages} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Finding Packages} - -{\Large The Python Package Index:} - -\vfill -{\LARGE PyPi} - -\vfill -\url{http://pypi.python.org/pypi} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Installing Packages} - -{\Large From source} -(\verb|setup.py install|) - -\vfill -{\Large With the system installer (apt-get, yum, etc...)} - -\vfill -{\Large From binaries: } - -\vfill -{\Large Windows:} MSI installers - -\vfill -{\Large OS-X:} dmg installers - -\vfill -{\Large And now:} binary wheels - -(make sure to get compatible packages) - -\vfill -{\Large \verb|easy_install| and \verb|pip|} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Installing Packages} - -{\Large In the beginning, there was the \verb|distutils|:} - -\url{....} - -{\Large But \verb|distutils| is missing some key features:} -\begin{itemize} - \item package versioning - \item package discovery - \item auto-install -\end{itemize} - -\vfill -{\Large - And then came \verb|PyPi|} - -\vfill -{\Large - And then came \verb|setuptools|} - -\vfill -{\Large - But that wasn't well maintained...} - -\vfill -{\Large - Then there was \verb|distribute/pip|} - -\vfill -{\Large - Which has now been merged back into \verb|setuptools|} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Installing Packages} - -\vfill -{\LARGE Actually, it's still a bit of a mess} -\vfill -{\large But getting better...} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Packaging Time line} - -{\centering -\includegraphics[width=4.5in]{PackagingTimeline.pdf} -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Packaging Tools} - -{\centering -\includegraphics[width=4.5in]{packaging1.pdf} -} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Current State of Packaging} - -\vfill -{\Large To build packages: distutils} - -\url{http://docs.python.org/2/distutils/} - -\vfill -{\Large For more features: setuptools} - -\url{http://pythonhosted.org/setuptools/} - -\vfill -{\Large To install packages: pip} - -\url{http://www.pip-installer.org/en/latest/} - -\vfill -{\Large For binary packages: wheels} - -\url{http://www.python.org/dev/peps/pep-0427/} - - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Compiled Packages} - -{\LARGE Biggest issue is with compiled extensions\\[0.1in] -\hfill(C/C++, etc)\hfill -} -\vfill -{\Large -- You need the right compiler set up} - -\vfill -{\LARGE Dependencies} - -\vfill -{\Large -- Here's were it gets really ugly} - -\vfill -{\Large -- Particularly on Windows} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Compiled Packages} - -{\LARGE Linux} - -\vfill -{\Large Pretty straightforward:} - -\vfill -{\Large 1) Is there a system package \\[0.1in] (rpm, deb, apt-get, etc...)? -} - -\vfill -{\Large 2) Install the dependencies, build from source:\\[0.1in] -\verb`python setup.py build ; python setup.py install` - -\vfill -( Or maybe \verb`pip install` will just work ) -} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Compiled Packages} - -{\LARGE Windows} - -\vfill -{\Large Sometimes simpler:} - -\vfill -{\Large 1) A lot of packages have Windows binaries:\\[0.1in] - - Usually for \url{python.org} builds \\[0.1in] - - Excellent source:} \url{http://www.lfd.uci.edu/~gohlke/pythonlibs/} \\[0.1in] -{\Large - Make sure you get 32 or 64 bit consistent -} - -\vfill -{\Large 2) But if no binaries: \\[0.1in] - - Hope the dependencies are available!\\[0.1in] - - Set up the compiler (MS VS2008 Express works) -} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Compiled Packages} - -{\LARGE OS-X} - -\vfill -{\Large Lots of Python versions:\\[0.1in] - - Apple's built-in (different for each version of OS)\\[0.1in] - - \url{python.org} builds.\\ - \hspace{0.5in}- 32 bit PPC+Intel\\ - \hspace{0.5in}- 32+64 bit Intel\\[0.1in] - - Macports - - Homebrew -} - - -\vfill -{\Large Binary Installers (dmg or wheel) have to match python version} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Compiled Packages} - -{\LARGE OS-X} - -\vfill -{\Large If you have to build it yourself:} - -\vfill -{\Large Xcode compiler (the right version):\\[0.1in] - - Version 3.* for 32 bit PPC+Intel\\[0.1in] - - Version 4.* for 32+64 bit Intel\\ -} - -\vfill -{\Large If extra dependencies:\\[0.1in] - - macports or home brew often easiest way to build them -} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Final Recommendation} - -{\Large First try: \verb|pip install|} - -\vfill -{\Large If that doesn't work:} - -\vfill -{\Large Read the docs of the package you want to install} - -\vfill -{\Large Do what they say} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{virtualenv} - -{\Large \verb|virtualenv| is a tool to create isolated Python environments.} - -\vfill -{\Large Very useful for developing multiple apps} - -\vfill -{\Large Or deploying more than one on one system} - -\vfill -\url{http://www.virtualenv.org/en/latest/index.html} - -\vfill -(Cris will get into more detail with this next class) - -\end{frame} - - -\section{Distributing} - -\begin{frame}[fragile]{Distributing} - -{\LARGE What if you need to distribute you own:} - -\vfill -{\Large Scripts} - -\vfill -{\Large Libraries } - -\vfill -{\Large Applications } -\vfill - -\end{frame} - -\begin{frame}[fragile]{Scripts} - -\vfill -{\LARGE Often you can just copy, share, or check in the script to source -control and call it good.} - -\vfill -{\Large But only if it's a single file, and doesn't need anything non-standard} - -\end{frame} - -\begin{frame}[fragile]{Scripts} - -\vfill -{\LARGE When the script needs more than just the stdlib\\ - (or your company standard environment)} - -\vfill -{\LARGE You have an application, not a script} - -\vfill - -\end{frame} - -\begin{frame}[fragile]{Libraries} - -\vfill -{\LARGE When you read the distutils docs, it's usually libraries they're talking about} - - -\vfill -{\LARGE Scripts + library is the same...} - - -\vfill -(\url{http://docs.python.org/distutils/}) -\end{frame} - -\begin{frame}[fragile]{distutils} - -\vfill -{\LARGE \verb|distutils| makes it easy to do the easy stuff:} - -\vfill -{\Large Distribute and install to multiple platforms, etc.} - -\vfill -{\Large Even binaries, installers and compiled packages} - -\vfill -{\Large (Except dependencies)} - -\vfill -(\url{http://docs.python.org/distutils/}) -\end{frame} - -\begin{frame}[fragile]{distutils basics} - -\vfill -{\Large It's all in the \verb|setup.py file|:} - -\begin{verbatim} -from distutils.core import setup -setup(name='Distutils', - version='1.0', - description='Python Distribution Utilities', - author='Greg Ward', - author_email='gward@python.net', - url='http://www.python.org/sigs/distutils-sig/', - packages=['distutils', 'distutils.command'], - ) -\end{verbatim} -\vfill -(\url{http://docs.python.org/distutils/}) -\end{frame} - -\begin{frame}[fragile]{distutils basics} - -{\Large Once your setup.py is written, you can:} - -\begin{verbatim} -python setup.py ... - -build build everything needed to install -install install everything from build directory -sdist create a source distribution - (tarball, zip file, etc.) -bdist create a built (binary) distribution -bdist_rpm create an RPM distribution -bdist_wininst create an executable installer for MS Windows -upload upload binary package to PyPI -\end{verbatim} - -\end{frame} - -%---------------------------------------------- -\begin{frame}[fragile]{More complex packaging} - -{\Large For a complex package:} - -\vfill -{\Large You want to use a well structured setup:} - -\vfill -\url{http://guide.python-distribute.org/creation.html} -\vfill -\end{frame} - -%---------------------------------------------- -\begin{frame}[fragile]{develop mode} - -{\Large While you are developing your package, Installing it is a pain.} - -\vfill -{\Large But you want your code to be able to import, etc. as though it were installed} - -\vfill -{\Large \verb|setup.py develop| installs links to your code, rather than copies - -- so it looks like it's installed, but it's using the original source} - -\vfill -{\Large \verb`python setup.py develop`} - -\vfill -{\Large You need \verb|setuptools| to use it.} -\vfill -\end{frame} - -%---------------------------------------------- -\begin{frame}[fragile]{Applications} - -{\Large For a complete application:} -\begin{itemize} - \item Web apps - \item GUI apps -\end{itemize} - -{\Large Multiple options:} -\begin{itemize} - \item Virtualenv + VCS - \item zc.buildout ( \url{http://www.buildout.org/} ) - \item System packages (rpm, deb, ...) - \item Bundles... -\end{itemize} - -\end{frame} - -%---------------------------------------------- -\begin{frame}[fragile]{Bundles} - -{\Large -Bundles are Python + all your code + plus all the dependencies -- -all in one single ``bundle'' - -\vfill -Most popular on Windows and OS-X -} -\begin{verbatim} - py2exe - py2app - pyinstaller - ... -\end{verbatim} - -{\Large User doesn't even have to know it's python } - -\vfill -Examples: \\ -\hspace{0.5in} \url{http://www.bitpim.org/} \\ -\hspace{0.5in} \url{http://response.restoration.noaa.gov/nucos} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\Large Write a setup.py for a script of yours} - -\begin{itemize} - \item Ideally, your script relies on at least one other module - \item At a minimum, you'll need to specify \verb|scripts| - \item and probably \verb|py_modules| - \item try: - \begin{itemize} - \item \verb| python setup.py build| - \item \verb| python setup.py install| - \item \verb| python setup.py sdist| - \item \verb| python setup.py bdist_wininst| - \end{itemize} - \item EXTRA: install \verb|setuptools| - \begin{itemize} - \item use: \verb|from setuptools import setup| - \item try: \verb| python setup.py develop| - \end{itemize} - -\vfill -(my example: capitalize Package) -\end{itemize} - -\end{frame} - - -%------------------------------- -\begin{frame}[fragile]{Homework} - -\vfill -{\LARGE Finish any labs...} - -\vfill -{\LARGE Your project} - -\vfill -{\LARGE Next week:} - -\vfill -{\Large Cris Ewing will come and talk about the next quarter} - -\vfill -\end{frame} - - -\end{document} - - diff --git a/slides_sources/old_versions/week-10/code/Solutions/add_book_data.py b/slides_sources/old_versions/week-10/code/Solutions/add_book_data.py deleted file mode 100644 index 6fa4b5d1..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/add_book_data.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -""" -sample data for persistence/serializatiion examples - -This version is nested, with more stucture - - can be saved with pickle, JSON, xml... -""" - -AddressBook = [ {'first_name': "Chris", - 'last_name': "Barker", - 'address' : {'line_1':"835 NE 33rd St", - 'line_2' : "", - 'city' : "Seattle", - 'state': "WA", - 'zip': "96543"}, - 'email' : "PythonCHB@gmail.com", - 'home_phone' : "206-555-1234", - 'office_phone' : "123-456-7890", - 'cell_phone' : "234-567-8901", - }, - - {'first_name': "Fred", - 'last_name': "Jones", - 'address' : {'line_1':"123 SE 13th St", - 'line_2' : "Apt. 43", - 'city' : "Tacoma", - 'state': "WA", - 'zip': "93465"}, - 'email' : "FredJones@some_company.com", - 'home_phone' : "510-555-1234", - 'office_phone' : "564-466-7990", - 'cell_phone' : "403-561-8911", - }, - - {'first_name': "Nancy", - 'last_name': "Wilson", - 'address' : {'line_1':"8654 Walnut St", - 'line_2' : "Suite 567", - 'city' : "Pasadena", - 'state': "CA", - 'zip': "12345"}, - 'email' : "Wilson.Nancy@gmail.com", - 'home_phone' : "423-321-9876", - 'office_phone' : "123-765-9877", - 'cell_phone' : "432-567-8466", - }, - ] - diff --git a/slides_sources/old_versions/week-10/code/Solutions/add_book_data_flat.py b/slides_sources/old_versions/week-10/code/Solutions/add_book_data_flat.py deleted file mode 100644 index 97a0869d..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/add_book_data_flat.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -""" -sample data for persistence/serialization examples -this version is flat for saving in CSV, ini, etc. -""" - -AddressBook = [ {'first_name': "Chris", - 'last_name': "Barker", - 'address_line_1':"835 NE 33rd St", - 'address_line_2' : "", - 'address_city' : "Seattle", - 'address_state': "WA", - 'address_zip': "96543", - 'email' : "PythonCHB@gmail.com", - 'home_phone' : "206-555-1234", - 'office_phone' : "123-456-7890", - 'cell_phone' : "234-567-8901", - }, - - {'first_name': "Fred", - 'last_name': "Jones", - 'address_line_1':"123 SE 13th St", - 'address_line_2' : "Apt. 43", - 'address_city' : "Tacoma", - 'address_state': "WA", - 'address_zip': "93465", - 'email' : "FredJones@some_company.com", - 'home_phone' : "510-555-1234", - 'office_phone' : "564-466-7990", - 'cell_phone' : "403-561-8911", - }, - - {'first_name': "Nancy", - 'last_name': "Wilson", - 'address_line_1':"8654 Walnut St", - 'address_line_2' : "Suite 567", - 'address_city' : "Pasadena", - 'address_state': "CA", - 'address_zip': "12345", - 'email' : "Wilson.Nancy@gmail.com", - 'home_phone' : "423-321-9876", - 'office_phone' : "123-765-9877", - 'cell_phone' : "432-567-8466", - }, - ] - diff --git a/slides_sources/old_versions/week-10/code/Solutions/anydbm_example.py b/slides_sources/old_versions/week-10/code/Solutions/anydbm_example.py deleted file mode 100644 index 3a73c1ce..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/anydbm_example.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data using the anydbm package - -""" - - -import anydbm - -outfilename = "add_book_data.dbm" - -# get the data from the py file -# csv format really only holds flat data well. -from add_book_data_flat import AddressBook - -## note that dbm files are really only good for simple key-value storage -## so let's just do one record: -person = AddressBook[0] - -# create a dbm file writing object -db = anydbm.open(outfilename, 'n') - -#write the data: -for key, value in person.items(): - db[key] = value - -#close the file -db.close() - -#### see if it can be re-loaded. -# -# open an existing dbm file -db = anydbm.open(outfilename, 'r') - -#read the data: -person = {} -for key, value in db.items(): - person[key] = value - -#Check if they are the same -if person == AddressBook[0]: - print "db version is the same as the original" - -### Storing multiple people: -## building up a key - -# left as an exercise for the reader.... - diff --git a/slides_sources/old_versions/week-10/code/Solutions/circle.py b/slides_sources/old_versions/week-10/code/Solutions/circle.py deleted file mode 100644 index 2544153b..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/circle.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -""" -Circle class -- my solution to the exercise - -Test code to run it is in test_circle.py -""" - -import math - -class Circle(object): - def __init__(self, radius): - self.radius = radius - - @classmethod - def from_diameter(cls, diameter): - return cls(diameter/2.0) - - @staticmethod - def circumference(radius): - return math.pi * 2 * radius - - @property - def diameter(self): - return self.radius * 2 - @diameter.setter - def diameter(self, value): - self.radius = value / 2.0 - - @property - def area(self): - return self.radius**2 * math.pi - - def __add__(self, other): - return Circle(self.radius + other.radius) - - def __repr__(self): - return "Circle(%f)"%self.radius - - def __str__(self): - return "Circle Object with radius: %f"%self.radius - diff --git a/slides_sources/old_versions/week-10/code/Solutions/csv_example.py b/slides_sources/old_versions/week-10/code/Solutions/csv_example.py deleted file mode 100644 index b47b7569..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/csv_example.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data as an CSV file with the CSV module - -""" - -import csv - -outfilename = "add_book_data.csv" - -# get the data from the py file -# csv format really only holds flat data well. -from add_book_data_flat import AddressBook - -# create a csv file writing object -writer = csv.writer( open(outfilename, 'wb') ) - -# write the headers -# assume all data have the same keys -headers = AddressBook[0].keys() -writer.writerow ( headers ) - -for person in AddressBook: - row = [person[key] for key in headers] - writer.writerow(row) - -del writer # to make sure the file gets closed - -### see if it can be re-loaded. - -# create a csv file reading object -reader = csv.reader( open(outfilename, 'rb') ) -# read the headers -headers = reader.next() # it's an iterator -- so next() gives us the next row -- in this case, the first row - -# build up the new version: -AddressBook2 = [] -for row in reader: - AddressBook2.append(dict(zip(headers, row))) - -del reader # to make sure the file is closed - -#Check if they are the same -if AddressBook2 == AddressBook: - print "csv readr version is the same as the original" - -## or use the built-in "DictReader": - -# create a DictReader file reading object -reader = csv.DictReader( open(outfilename, 'rb') ) -# no need to read the headers -- it will use the first row - -# build up the new version: -AddressBook3 = [] -for row in reader: - print "row:", row - AddressBook3.append(row) - -del reader # to make sure the file is closed - -#Check if they are the same -if AddressBook3 == AddressBook: - print "The DictReader one is the the same" - diff --git a/slides_sources/old_versions/week-10/code/Solutions/indent_etree.py b/slides_sources/old_versions/week-10/code/Solutions/indent_etree.py deleted file mode 100644 index 7bc3a691..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/indent_etree.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -""" -indenting function to pretty-print an ElementTree - -from: - -http://infix.se/2007/02/06/gentlemen-indent-your-xml - -why the %*#^ this isn't built-in to etree is beyond me. - -usage: - -indent(tree.getroot()) - -tree.write(outfilename) - -""" - -def indent(elem, level=0): - i = "\n" + level*" " - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - for e in elem: - indent(e, level+1) - if not e.tail or not e.tail.strip(): - e.tail = i + " " - if not e.tail or not e.tail.strip(): - e.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - diff --git a/slides_sources/old_versions/week-10/code/Solutions/ini_file_example.py b/slides_sources/old_versions/week-10/code/Solutions/ini_file_example.py deleted file mode 100644 index 30393b66..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/ini_file_example.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data as an "ini" file with ConfigParser - -""" - -import ConfigParser - -outfilename = "addresses.ini" - -# get the data from the py file -# ini format really only holds flat data well. -from add_book_data_flat import AddressBook - -# save it in an ini file -data = ConfigParser.ConfigParser() - -for i, person in enumerate(AddressBook): - sec_name = 'person%i'%i - data.add_section(sec_name) - for key,value in person.items(): - data.set(sec_name, key, value) - -data.write( open("add_book.ini",'w') ) - -## see if we can re-load it -data = data = ConfigParser.ConfigParser() -data.read("add_book.ini") - -#extract the data and put into a list of dicts: -AddressBook2 = [] -for sec_name in data.sections(): - AddressBook2.append( dict( data.items(sec_name) ) ) -print AddressBook2 - -if AddressBook2 == AddressBook: - print "they are the same" - diff --git a/slides_sources/old_versions/week-10/code/Solutions/json_example.py b/slides_sources/old_versions/week-10/code/Solutions/json_example.py deleted file mode 100644 index 2b942a42..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/json_example.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data as json - -""" - -import json - -outfilename = "add_book_data.json" - -# get the data from the py file -from add_book_data import AddressBook - -# dump it as json (it's really this simple) -json.dump(AddressBook, open(outfilename, 'wb') ) -#json.dump(AddressBook, open(outfilename, 'wb'), indent=4 ) # specifying indent pretty-prints the json - -### see if we can re-load it - -AddressBook2 = json.load( open(outfilename, 'rb') ) - -if AddressBook2 == AddressBook: - print "json version is the same as the original" - diff --git a/slides_sources/old_versions/week-10/code/Solutions/pickle_example.py b/slides_sources/old_versions/week-10/code/Solutions/pickle_example.py deleted file mode 100644 index 3d711d5f..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/pickle_example.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data in a pickle - -""" - -import cPickle as pickle - -outfilename = "add_book_data.pickle" - -# get the data from the py file -from add_book_data import AddressBook - -# pickle it (it's really this simple) -pickle.dump(AddressBook, open(outfilename, 'wb') ) - -## see if we can re-load it - -AddressBook2 = pickle.load( open(outfilename, 'rb') ) - -if AddressBook2 == AddressBook: - print "pickeld/unpickled version is the same as the original" - diff --git a/slides_sources/old_versions/week-10/code/Solutions/pickle_example2.py b/slides_sources/old_versions/week-10/code/Solutions/pickle_example2.py deleted file mode 100644 index ab8764a4..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/pickle_example2.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save custom classes in a pickle -""" - -import cPickle as pickle - -outfilename = "circles.pickle" - -### You can pickle a custom class, too: -# remember the Circle class? - -import circle - -# create a couple of circles: - -C1 = circle.Circle(radius=2) -print C1 - -C2 = circle.Circle(radius=3.4) -print C2 - -# put them in a dict: -circles = {'circle1': C1, - 'circle2': C2} - -#print circles - -## pickle the list -pickle.dump(circles, open(outfilename, 'wb') ) - -### see if we can re-load it - -## Note: the circle module needs to be available when you load the pickle -circles2 = pickle.load( open(outfilename, 'rb') ) - -# Haven't defined compare for the circle class: -## extra credit -- add compare method (__cmp__) to Circle class -same = True -for c1, c2 in zip(circles.values(), circles2.values()): - if c1.radius != c2.radius: - same = False - break - -if same: - print "pickled/unpickled version is the same as the original" -else: - print "not the same" - print circles - print circles2 \ No newline at end of file diff --git a/slides_sources/old_versions/week-10/code/Solutions/python_literal.py b/slides_sources/old_versions/week-10/code/Solutions/python_literal.py deleted file mode 100644 index 0549c3b2..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/python_literal.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data as python literals in a py file - -""" - -outfilename = "add_book_data.pyliteral" - -# get the data from the py file -from add_book_data import AddressBook - -# save it as python literals: - -outfile = open(outfilename, 'w') - -outfile.write(str(AddressBook)) - -outfile.close() - -## see if we can re-load it - -data = open(outfilename, 'r').read() - -AddressBook2 = eval(data) - -if AddressBook2 == AddressBook: - print "they are the same" - -## try again with the pretty print version: -import pprint - -outfilename = "add_book_data.pyliteral_pretty" - -outfile = open(outfilename, 'w') - -outfile.write(pprint.pformat(AddressBook)) - -outfile.close() - -## see if we can re-load it -data = open(outfilename, 'r').read() - -AddressBook2 = eval(data) - -if AddressBook2 == AddressBook: - print "pretty printed version is the same as well" - \ No newline at end of file diff --git a/slides_sources/old_versions/week-10/code/Solutions/shelve_example.py b/slides_sources/old_versions/week-10/code/Solutions/shelve_example.py deleted file mode 100644 index 2aa9a0fd..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/shelve_example.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data in a shelf - -""" - -import shelve - -outfilename = "add_book_data.shelve" - -# get the data from the py file -from add_book_data import AddressBook - -# since we can put a whole dict on a shelf: -shelf = shelve.open(outfilename, 'n') - -for person in AddressBook: - # create a key: - key = "%(first_name)s%(last_name)s"%person - shelf[key] = person - -shelf.close() - -## see if we can re-load it - -shelf2 = shelve.open(outfilename) - -AddressBook2 = [person for person in shelf2.values()] -## note -- there could be an issue with order here. -## so: -AddressBook.sort() -AddressBook2.sort() - -if AddressBook2 == AddressBook: - print "shelved/unshelved version is the same as the original" - diff --git a/slides_sources/old_versions/week-10/code/Solutions/sqlite_example.py b/slides_sources/old_versions/week-10/code/Solutions/sqlite_example.py deleted file mode 100644 index 31e60abf..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/sqlite_example.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python - -""" -Example of using sqlite3 module for a relational database -""" - -import sqlite3, os - -db_filename = "add_book_data.sqlite" # any extension will do -- *.db and *.sqlite are common - -# get the data from the py file -from add_book_data_flat import AddressBook - -# if the db already exists -- delete it: -try: - os.remove(db_filename) -except OSError: - print "no db file there yet" - -# create a connection to an sqlite db file: -conn = sqlite3.connect(db_filename) -# NOTE: you can do an in-memory version: -#conn = sqlite3.connect(":memory:") - -# establish the schema (single table in this case...): -# Create a table -conn.execute("""CREATE TABLE addresses - ( first_name text, - last_name text, - address_line_1 text, - address_line_2 text, - address_city text, - address_state text, - address_zip text, - email text, - home_phone text, - office_phone text, - cell_phone text - )""" - ) -conn.commit() - -# get the fields from the data: -fields = AddressBook[0].keys() -# order matters, so we sort to make sure they will always be in the same order -fields.sort() - -# add some data: -# get a cursor: -c = conn.cursor() -for person in AddressBook: - # Insert a row of data - row = [ person[field] for field in fields ] - row = "','".join(row) - sql = "INSERT INTO addresses VALUES ('%s')"%row - #print sql - c.execute(sql) - -# Save (commit) the changes and close the connection -conn.commit() -conn.close() - - -### see if we can re-load it -conn = sqlite3.connect(db_filename) - -sql = "SELECT * FROM addresses" -# no need for a cursor if a single sql statement needs to be run -result = conn.execute(sql) - -## put it all back in a list of dicts -AddressBook2 = [] -for row in result: - d = dict(zip(fields, row)) - AddressBook2.append(d) - -if AddressBook2 == AddressBook: - print "the version pulled from sqlite is the same as the original" -else: - print "they don't match!" - -conn.close() - -## now do it with the non-flat version -- with a proper schema - -# left as an exercise for the reader - - - diff --git a/slides_sources/old_versions/week-10/code/Solutions/xml_example.py b/slides_sources/old_versions/week-10/code/Solutions/xml_example.py deleted file mode 100644 index 60067d3b..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/xml_example.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data as xml, using the element tree module - -This version stores all the data as attributes - -""" - -import xml.etree.ElementTree as ET -from indent_etree import indent # for prettier output - -outfilename = "add_book_data.xml" - -# get the data from the py file -from add_book_data_flat import AddressBook - -# build a tree structure -root = ET.Element("address_book") - -# add the elements: -for person in AddressBook: - p = ET.SubElement(root, "person") - # This method stores everything in attributes - for key,value in person.items(): - p.set(key, value) - -# wrap it in an ElementTree instance, and save as XML -tree = ET.ElementTree(root) - -indent(tree.getroot()) # to make it more pretty -tree.write(outfilename) - -### See if we can re-load it - -tree = ET.parse(outfilename) -book = tree.getroot() -# re-build the original list: -AddressBook2 = [] -for person in book.getchildren(): - #print person.attrib - AddressBook2.append(person.attrib) - -if AddressBook2 == AddressBook: - print "xml version is the same as the original" - diff --git a/slides_sources/old_versions/week-10/code/Solutions/xml_example2.py b/slides_sources/old_versions/week-10/code/Solutions/xml_example2.py deleted file mode 100644 index d0f819b2..00000000 --- a/slides_sources/old_versions/week-10/code/Solutions/xml_example2.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - -""" -Example of how to save data as xml, using the element tree module - -This version uses the nested dataset, and does full-on nested XML - -""" - -import xml.etree.ElementTree as ET -from indent_etree import indent # for prettier output - -outfilename = "add_book_data2.xml" - -# get the data from the py file -from add_book_data import AddressBook - -# build a tree structure -root = ET.Element("address_book") - -# add the elements: -for person in AddressBook: - p = ET.SubElement(root, "person") - # This method stores everything as sub-elements - for key, value in person.items(): - if type(value) == dict: - address = ET.SubElement(p, 'address') - for sub_key, sub_value in value.items(): - sub_el = ET.SubElement(address, sub_key) - sub_el.text=sub_value - else: - el = ET.SubElement(p, key) - el.text=value - -# wrap it in an ElementTree instance, and save as XML -tree = ET.ElementTree(root) - -indent(tree.getroot()) # to make it more pretty -tree.write(outfilename) - -### See if we can re-load it - -tree = ET.parse(outfilename) -book = tree.getroot() -# re-build the original list: -AddressBook2 = [] -for person in list(book): - p = {} - for sub_el in list(person): - if sub_el.tag == "address": - address = {} - for sub_sub_el in sub_el.getchildren(): - t = sub_sub_el.text - if t is None: ## etree returns None for empty tags! - address[sub_sub_el.tag] = "" - else: - address[sub_sub_el.tag] = t - p['address'] = address - else: - p[sub_el.tag] = sub_el.text - AddressBook2.append(p) - -if AddressBook2 == AddressBook: - print "xml version is the same as the original" -else: - print "xml version is not exactly the same as the original" diff --git a/slides_sources/old_versions/week-10/code/add_book_data.py b/slides_sources/old_versions/week-10/code/add_book_data.py deleted file mode 100644 index 6fa4b5d1..00000000 --- a/slides_sources/old_versions/week-10/code/add_book_data.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -""" -sample data for persistence/serializatiion examples - -This version is nested, with more stucture - - can be saved with pickle, JSON, xml... -""" - -AddressBook = [ {'first_name': "Chris", - 'last_name': "Barker", - 'address' : {'line_1':"835 NE 33rd St", - 'line_2' : "", - 'city' : "Seattle", - 'state': "WA", - 'zip': "96543"}, - 'email' : "PythonCHB@gmail.com", - 'home_phone' : "206-555-1234", - 'office_phone' : "123-456-7890", - 'cell_phone' : "234-567-8901", - }, - - {'first_name': "Fred", - 'last_name': "Jones", - 'address' : {'line_1':"123 SE 13th St", - 'line_2' : "Apt. 43", - 'city' : "Tacoma", - 'state': "WA", - 'zip': "93465"}, - 'email' : "FredJones@some_company.com", - 'home_phone' : "510-555-1234", - 'office_phone' : "564-466-7990", - 'cell_phone' : "403-561-8911", - }, - - {'first_name': "Nancy", - 'last_name': "Wilson", - 'address' : {'line_1':"8654 Walnut St", - 'line_2' : "Suite 567", - 'city' : "Pasadena", - 'state': "CA", - 'zip': "12345"}, - 'email' : "Wilson.Nancy@gmail.com", - 'home_phone' : "423-321-9876", - 'office_phone' : "123-765-9877", - 'cell_phone' : "432-567-8466", - }, - ] - diff --git a/slides_sources/old_versions/week-10/code/add_book_data_flat.py b/slides_sources/old_versions/week-10/code/add_book_data_flat.py deleted file mode 100644 index 97a0869d..00000000 --- a/slides_sources/old_versions/week-10/code/add_book_data_flat.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -""" -sample data for persistence/serialization examples -this version is flat for saving in CSV, ini, etc. -""" - -AddressBook = [ {'first_name': "Chris", - 'last_name': "Barker", - 'address_line_1':"835 NE 33rd St", - 'address_line_2' : "", - 'address_city' : "Seattle", - 'address_state': "WA", - 'address_zip': "96543", - 'email' : "PythonCHB@gmail.com", - 'home_phone' : "206-555-1234", - 'office_phone' : "123-456-7890", - 'cell_phone' : "234-567-8901", - }, - - {'first_name': "Fred", - 'last_name': "Jones", - 'address_line_1':"123 SE 13th St", - 'address_line_2' : "Apt. 43", - 'address_city' : "Tacoma", - 'address_state': "WA", - 'address_zip': "93465", - 'email' : "FredJones@some_company.com", - 'home_phone' : "510-555-1234", - 'office_phone' : "564-466-7990", - 'cell_phone' : "403-561-8911", - }, - - {'first_name': "Nancy", - 'last_name': "Wilson", - 'address_line_1':"8654 Walnut St", - 'address_line_2' : "Suite 567", - 'address_city' : "Pasadena", - 'address_state': "CA", - 'address_zip': "12345", - 'email' : "Wilson.Nancy@gmail.com", - 'home_phone' : "423-321-9876", - 'office_phone' : "123-765-9877", - 'cell_phone' : "432-567-8466", - }, - ] - diff --git a/slides_sources/old_versions/week-10/code/example.cfg b/slides_sources/old_versions/week-10/code/example.cfg deleted file mode 100644 index c27f2939..00000000 --- a/slides_sources/old_versions/week-10/code/example.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[Section1] -int = 15 -bool = true -float = 3.1415 - -[Section2] -int = 32 -bool = False -float = 1.4235 \ No newline at end of file diff --git a/slides_sources/old_versions/week-10/code/switch_case.py b/slides_sources/old_versions/week-10/code/switch_case.py deleted file mode 100644 index ac72555a..00000000 --- a/slides_sources/old_versions/week-10/code/switch_case.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python - -""" -Spelling switch/case with a dictionary -""" - -""" -A switch/case example: -switch(n) { - case 0: - printf("You typed zero.\n"); - break; - case 1: - case 9: - printf("n is a perfect square\n"); - break; - case 2: - printf("n is an even number\n"); - case 3: - case 5: - case 7: - printf("n is a prime number\n"); - break; - case 4: - printf("n is a perfect square\n"); - case 6: - case 8: - printf("n is an even number\n"); - break; - default: - printf("Only single-digit numbers are allowed\n"); - break; -} -""" -def zero(): - return "You typed zero.\n" - -def sqr(): - return "n is a perfect square\n" - -def even(): - return "n is an even number\n" - -def prime(): - return "n is a prime number\n" - -options = { 0 : zero, - 1 : sqr, - 4 : sqr, - 9 : sqr, - 2 : even, - 3 : prime, - 5 : prime, - 7 : prime, - } - -print options[2]() - -print options[4]() - diff --git a/slides_sources/old_versions/week-10/presentation-week-10.pdf b/slides_sources/old_versions/week-10/presentation-week-10.pdf deleted file mode 100644 index 1766b291..00000000 Binary files a/slides_sources/old_versions/week-10/presentation-week-10.pdf and /dev/null differ diff --git a/slides_sources/old_versions/week-10/presentation-week-10.tex b/slides_sources/old_versions/week-10/presentation-week-10.tex deleted file mode 100644 index 376b6ec8..00000000 --- a/slides_sources/old_versions/week-10/presentation-week-10.tex +++ /dev/null @@ -1,980 +0,0 @@ -\documentclass{beamer} -%\usepackage[latin1]{inputenc} -\usetheme{Warsaw} -\title[Intro to Python: Week 1]{Introduction to Python\\ -Persistence / Serialization} -\author{Christopher Barker} -\institute{UW Continuing Education} -\date{December 10, 2013} - -\usepackage{listings} -\usepackage{hyperref} - -\begin{document} - -% --------------------------------------------- -\begin{frame} - \titlepage -\end{frame} - -% --------------------------------------------- -\begin{frame} -\frametitle{Table of Contents} -%\tableofcontents[currentsection] - \tableofcontents -\end{frame} - - -\section{Review/Questions} - -% --------------------------------------------- -\begin{frame}{Review of Previous Class} - -{\Large -\begin{itemize} - \item Decorators - \item Context Managers - \item Packaging -\end{itemize} -} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Lightning Talks} - -\vfill -{\LARGE Lightning talks today:} - -\vfill -{\Large -\vfill -Andrew Bae - -\vfill -Travis Grizzel - -\vfill -Adam Leblanc - -} -\vfill - -\end{frame} - - -% --------------------------------------------- -\begin{frame}{Projects} - - \vfill - {\Large Due Dec 14th, 11:59pm PST } - - \vfill - {\Large Email them to me} - - \vfill - {\Large Questions?} - - \vfill - {\large Note: private github project -- should I make it public?} - -\end{frame} - -%------------------------------- -\begin{frame}{Evaluations} - -\vfill -{\Large UWPCE wants you to fill out course evaluations...} - -\vfill -{\Large I need a volunteer: -\begin{itemize} - \item Collect the evals... - \item Mail them in to UWPCE -\end{itemize} -} - -\vfill -{\Large pLease fill them out during the class period} - -\vfill -{\large Yes, I do have a handful of \#2 pencils...} - -\end{frame} - - -%############################## -\section{Web Development Class} - -\begin{frame}[fragile]{Internet Programming in Python} - -\vfill -{\LARGE Internet Programming in Python } - -\vfill -{\LARGE Cris Ewing} - -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talks} - -{\LARGE Lightning Talks:} - -\vfill -{\Large Andrew Bae } - -\vfill -{\Large Travis Grizzel } - -\vfill - -\end{frame} - -% ---------------------------------------------- -\begin{frame}[fragile]{Side note:} - -{\Large How do you spell switch/case in Python?} - -\vfill -{\hspace{0.2in} Hint: NOT with a lot of \verb`elif`s} - -\vfill -{\Large Use a dict:} - -\vfill -{\Large Put the values to switch on in the keys:} - -\vfill -{\Large Functions to call in values:} - -\vfill -demo: sample code (\verb|switch_case.py|) -\end{frame} - - - -% --------------------------------------------- -\begin{frame}{This Class} - -\vfill -{\Large Today is less about concepts} - -\vfill -{\Large More about learning to use a given module} - -\vfill -{\Large So less talk, more coding} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Serialization} - -\vfill -{\Large I'm focusing on methods available in the Python standard library} - -\vfill -{\Large Serialization is the process of putting your potentially complex -(and nested) python data structures into a linear (serial) form .. i.e. a string of bytes.} - -\vfill -{\Large The serial form can be saved to a file, pushed over the wire, etc.} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Persistence} - -\vfill -{\Large Persistence is saving your python data structure(s) to disk -- so they -will persist once the python process is finished.} - -\vfill -{\Large Any serial form can provide persistence (by dumping/loading it to/from -a file), but not all persistence mechanisms are serial (i.e RDBMS)} - - -\vfill -\url{http://wiki.python.org/moin/PersistenceTools} -\end{frame} - - -\section{Python Specific Formats} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Literals} - -\vfill -{\Large Putting plain old python literals in your file} - -\vfill -{\Large Gives a nice, human-editable form for config files, etc.} - -\vfill -{\Large Don't use for untrusted sources!!!} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Literals} - -\vfill -{\Large Good for basic python types.} -(can work for your own classes, too -- if you write a good \verb|__repr__|) - -\vfill -{\Large In theory, \verb|repr()| always gives a form that can be re-constructed.} - -\vfill -{\Large Often \verb|str()| form works too.} - -\vfill -{\Large \verb|pprint| (pretty print) module can make it easier to read.} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python Literal Example} - -{\small -\begin{verbatim} -# a list of dicts -data = [{'this':5, 'that':4}, {'spam':7, 'eggs':3.4}] - -In [51]: s = repr(data) # save a string version: - -In [52]: data2 = eval(s) # re-construct with eval: - -In [53]: data2 == data # they are equal -Out[53]: True - -In [54]: data is data2 # but not the same object -Out[54]: False -\end{verbatim} -} -You can save the string to a file and even use \verb|import| -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{pretty print} - -{\small -\begin{verbatim} -In [69]: import pprint - -In [71]: repr(data) -Out[71]: "[{'this': 5, 'that': 4}, {'eggs': 3.4, 'spam': 7}, {'foo': 86, 'bar': 4.5}, {'fun': 43, 'baz': 6.5}]" - -In [72]: s = pprint.pformat(data) - -In [73]: print s -[{'that': 4, 'this': 5}, - {'eggs': 3.4, 'spam': 7}, - {'bar': 4.5, 'foo': 86}, - {'baz': 6.5, 'fun': 43}] -\end{verbatim} -} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Pickle} - -\vfill -{\Large Pickle is a binary format for python objects} - -\vfill -{\Large You can essentially dump any python object to disk (or string, or socket, or...} - -\vfill -{\Large \verb|cPickle| is faster than pickle, but -can't be customized -- you usually want \verb|cPickle|} - -\vfill -\url{http://docs.python.org/library/pickle.html} -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Pickle} - -{\small -\begin{verbatim} -In [87]: import cPickle as pickle -In [83]: data -Out[83]: -[{'that': 4, 'this': 5}, - {'eggs': 3.4, 'spam': 7}, - {'bar': 4.5, 'foo': 86}, - {'baz': 6.5, 'fun': 43}] -In [84]: pickle.dump(data, open('data.pkl', 'wb')) -In [85]: data2 = pickle.load(open('data.pkl', 'rb')) -In [86]: data2 == data -Out[86]: True -\end{verbatim} -} - -\vfill -\url{http://docs.python.org/library/pickle.html} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Shelve} - -\vfill -{\Large A ``shelf'' is a persistent, dictionary-like object} - -\vfill -{\Large The values (not the keys!) can be essentially arbitrary Python -objects (anything picklable)} - -\vfill -{\Large NOTE: will not reflect changes in mutable objects without - re-writing them to the db.}\\ - (or use writeback=True) - -\vfill -{\Large If less that 100s of MB -- just use a dict and pickle it.} - -\vfill -\url{http://docs.python.org/library/shelve.html} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Shelve} - -{\Large \verb|shelve| presents a \verb|dict| interface:} -\begin{verbatim} -import shelve - -d = shelve.open(filename) -d[key] = data # store data at key -data = d[key] # retrieve a COPY of data at key -del d[key] # delete data stored at key -flag = d.has_key(key) # true if the key exists - -d.close() # close it -\end{verbatim} - -\vfill -\url{http://docs.python.org/library/shelve.html} -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -{\large There are two datasets in the \verb|code| dir:} - -\begin{verbatim} -add_book_data.py -add_book_data_flat.py -# load with: -from add_book_data import AddressBook -\end{verbatim} - -They have address book data -- one with a nested dict, one "flat" - -\begin{itemize} - \item Write a module that saves the data as python literals in a file\\ - --- and reads it back in - \item Write a module that saves the data as a pickle in a file\\ - --- and reads it back in - \item Write a module that saves the data in a shelve\\ - --- and accesses it one by one. -\end{itemize} - -\end{frame} - -%------------------------------- -\begin{frame}{Lightning Talk} - -{\LARGE Lightning Talk:} - -\vfill -{\Large Adam Leblanc} - -\vfill - -\end{frame} - - -\section{Interchange Formats} - -\begin{frame}[fragile]{INI} - -{\Large INI files} - -(the old Windows config files) - -\begin{verbatim} -[Section1] -int = 15 -bool = true -float = 3.1415 - -[Section2] -int = 32 -... -\end{verbatim} -\vfill -{\Large Good for configuration data, etc.} -\end{frame} - -\begin{frame}[fragile]{ConfigParser} - -{\Large Writing \verb|ini| files:} - -\begin{verbatim} -import ConfigParser -config = ConfigParser.ConfigParser() - -config.add_section('Section1') -config.set('Section1', 'int', '15') -config.set('Section1', 'bool', 'true') -config.set('Section1', 'float', '3.1415') - -# Writing our configuration file to 'example.cfg' -config.write( open('example.cfg', 'wb') ) -\end{verbatim} - -\vfill -Note: all keys and values are strings -\end{frame} - -\begin{frame}[fragile]{ConfigParser} - -{\Large Reading \verb|ini| files:} - -\begin{verbatim} ->>> config = ConfigParser.ConfigParser() ->>> config.read('example.cfg') ->>> config.sections() -['Section1', 'Section2'] - ->>> config.get('Section1', 'float') -'3.1415' ->>> config.items('Section1') -[('int', '15'), ('bool', 'true'), ('float', '3.1415')] -\end{verbatim} - -\vfill -\url{http://docs.python.org/library/configparser.html} -\end{frame} - -\begin{frame}[fragile]{CSV} - -{\Large CSV (Comma Separated Values) format is the -most common import and export format for spreadsheets and databases.} - -\vfill -{\Large No real standard -- the Python csv package more or less follows MS Excel standard} - -(with other "dialects" available) - -\vfill -{\Large Can use delimiters other than commas...}\\ -(I like tabs better) - -\vfill -{\Large Most useful for simple tabular data} - -\end{frame} - -%---------------------------------- -\begin{frame}[fragile]{CSV module} - -{\Large Reading \verb|CSV| files:} - -\begin{verbatim} ->>> import csv ->>> spamReader = csv.reader( open('eggs.csv', 'rb') ) ->>> for row in spamReader: -... print ', '.join(row) -Spam, Spam, Spam, Spam, Spam, Baked Beans -Spam, Lovely Spam, Wonderful Spam -\end{verbatim} - -\vfill -{\verb|csv| module takes care of string quoting, etc. for you} - -\vfill -\url{http://docs.python.org/library/csv.html} -\end{frame} - - - -\begin{frame}[fragile]{CSV module} - -{\Large Writing \verb|CSV| files:} - -\begin{verbatim} ->>> import csv ->>> spamWriter = csv.writer(open('eggs.csv', 'wb'), - quoting=csv.QUOTE_MINIMAL) ->>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans']) ->>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam']) -\end{verbatim} - -\vfill -{\verb|csv| module takes care of string quoting, etc for you} - -\vfill -\url{http://docs.python.org/library/csv.html} -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{JSON} - -\vfill -{\Large JSON (JavaScript Object Notation) is a subset of JavaScript syntax - used as a lightweight data interchange format.} - -\vfill -{\Large Python module has an interface similar to pickle} - -\vfill -{\Large Can handle the standard Python data types} - -\vfill -{\Large Specializable encoding/decoding for other types -- but I wouldn't do that!} - -\vfill -{\Large Presents a similar interface as \verb|pickle|} - -\vfill -\url{http://www.json.org/}\\ -\url{http://docs.python.org/library/json.html} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{Python json module} - -{\small -\begin{verbatim} -In [94]: s = json.dumps(data) - -Out[95]: '[{"this": 5, "that": 4}, {"eggs": 3.4, "spam": 7}, - {"foo": 86, "bar": 4.5}, {"fun": 43, "baz": 6.5}]' - # looks a lot like python literals... -In [96]: data2 = json.loads(s) - -Out[97]: -[{u'that': 4, u'this': 5}, - {u'eggs': 3.4, u'spam': 7}, -... -In [98]: data2 == data -Out[98]: True # they are the same - -\end{verbatim} -} -(also \verb|json.dump() and json.load()| for files) -\vfill -\url{http://docs.python.org/library/json.html} -\end{frame} - - - -% --------------------------------------------- -\begin{frame}[fragile]{XML} - -\vfill -{\Large XML is a standardized version of SGML, designed for use as a data - storage / interchange format.} - -\vfill -{\Large NOTE: HTML is also SGML, and modern versions conform to the XML standard.} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{XML in the python std lib} - - -\vfill -{\Large \verb|xml.dom|: } - -\vfill -{\Large \verb|xml.sax|: } - -\vfill -{\Large \verb|xml.parsers.expat|: } - -\vfill -{\Large \verb|xml.etree|: } - -\url{http://docs.python.org/library/xml.etree.elementtree.html} - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{elementtree} - - -\vfill -{\Large The Element type is a flexible container object, designed to store -hierarchical data structures in memory.} - -\vfill -{\Large Essentially an in-memory XML -- can be read from / written-to XML} - -\vfill -{\Large an \verb`ElementTree` is an entire XML doc} - -\vfill -{\Large an \verb`Element` is a node in that tree} - -\vfill -\url{http://docs.python.org/library/xml.etree.elementtree.html} - -\end{frame} - -%------------------------------- -\begin{frame}[fragile]{LAB} - -\begin{verbatim} -# load with: -from add_book_data import AddressBook -\end{verbatim} - -They have address book data -- one with a nested dict, one "flat" - -\begin{itemize} - \item Write a module that saves the data as an INI file\\ - --- and reads it back in - \item Write a module that saves the data as a CSV file\\ - --- and reads it back in - \item Write a module that saves the data in JSON\\ - --- and reads it back in - \item Write a module that saves the data in XML\\ - --- and reads it back in \\ - --- this gets ugly! -\end{itemize} - -\end{frame} - - -\section{DataBases} - -% --------------------------------------------- -\begin{frame}[fragile]{anydbm} - -\vfill -{\Large \verb|anydbm| is a generic interface to variants of the DBM database} - -\vfill -{\Large Suitable for storing data that fits well into a python dict with strings as both keys and values} - -\vfill -{\Large Note: anydbm will use the dbm system that works on your system -- - this may be different on different systems -- so the db files may NOT - be compatible! \verb|whichdb| will try to figure it out, but it's not - guaranteed} -\vfill -\url{http://docs.python.org/library/anydbm.html} -\end{frame} - -\begin{frame}[fragile]{anydbm module} - -{\Large Writing data:} - -\begin{verbatim} -#creating a dbm file: -anydbm.open(filename, 'n') -\end{verbatim} - -{\large flag options are: } -\begin{description} - \item['r'] Open existing database for reading only (default) - \item['w'] Open existing database for reading and writing - \item['c'] Open database for reading and writing, creating it if it doesn’t exist - \item['n'] Always create a new, empty database, open for reading and writing -\end{description} -\vfill -\url{http://docs.python.org/library/anydbm.html} -\end{frame} - -\begin{frame}[fragile]{anydbm module} - -{\Large \verb|dbm| provides dict-like interace:} - -\begin{verbatim} -db = dbm.open("dbm", "c") - -db["first"] = "bruce" -db["second"] = "micheal" -db["third"] = "fred" -db["second"] = "john" #overwrite -db.close() -# read it: -db = dbm.open("dbm", "r") -for key in db.keys(): - print key, db[key] -\end{verbatim} - -\vfill -\url{http://docs.python.org/library/anydbm.html} -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{sqlite} - -\vfill -{\Large SQLite: C library provides a lightweight disk-based single-file database} - -\vfill -{\Large Nonstandard variant of the SQL query language} - -\vfill -{\Large Very broadly used as as an embedded databases for storing - application-specific data etc.} - -\vfill -Firefox plug-in:\\ -\url{https://addons.mozilla.org/en-US/firefox/addon/sqlite-manager/} -\end{frame} - -\begin{frame}[fragile]{python sqlite module} - -\vfill -{\Large \verb|sqlite3| Python module wraps C lib -- provides standard DB-API interface} - -\vfill -{\Large Allows (and require SQL queries} - -\vfill -{\Large Can provide high performance, flexible, portable storage for your app} - -\vfill -\url{http://docs.python.org/library/sqlite3.html} -\end{frame} - -%--------------------------------- -\begin{frame}[fragile]{python sqlite module} - -{\Large Example:} - -\begin{verbatim} -import sqlite3 -# open a connection to a db file: -conn = sqlite3.connect('example.db') - -# or build one in-memory -conn = sqlite3.connect(':memory:') - -# create a cursor -c = conn.cursor() -\end{verbatim} - -\vfill -\url{http://docs.python.org/library/sqlite3.html} -\end{frame} - - -%--------------------------------- -\begin{frame}[fragile]{python sqlite module} - -{\Large Execute SQL with the cursor:} - -\begin{verbatim} -# Create table -c.execute('''CREATE TABLE stocks - (date text, trans text, symbol text, qty real, price real)''') -# Insert a row of data -c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") -# Save (commit) the changes -conn.commit() -# Close the cursor if we are done with it -c.close() -\end{verbatim} - -\vfill -\url{http://docs.python.org/library/sqlite3.html} -\end{frame} - -%--------------------------------- -\begin{frame}[fragile]{python sqlite module} - -{\large \verb|SELECT| creates an cursor that can be iterated:} - -\begin{verbatim} ->>> for row in c.execute('SELECT * FROM stocks ORDER BY price'): - print row - -(u'2006-01-05', u'BUY', u'RHAT', 100, 35.14) -(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0) -... -\end{verbatim} - -{\large Or you can get the rows one by one or in a list:} - -\begin{verbatim} - c.fetchone() - c.fetchall() -\end{verbatim} - -\end{frame} - - -%--------------------------------- -\begin{frame}[fragile]{python sqlite module} - -\vfill -{\large Good idea to use the DB-API’s parameter substitution:} - -\begin{verbatim} -t = (symbol,) -c.execute('SELECT * FROM stocks WHERE symbol=?', t) -print c.fetchone() - -# Larger example that inserts many records at a time -purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), - ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00), - ('2006-04-06', 'SELL', 'IBM', 500, 53.00), - ] -c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases) -\end{verbatim} - -\vfill -\url{http://xkcd.com/327/} -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{DB-API} - -\vfill -{\Large The DB-API spec (PEP 249) is a specification for interaction between Python and Relational Databases.} - -\vfill -{\Large Support for a large number of third-party Database drivers: -\begin{itemize} - \item MySQL - \item PostgreSQL - \item Oracle - \item MSSQL (?) - \item ..... -\end{itemize} -} -\vfill -\url{http://www.python.org/dev/peps/pep-0249} -\end{frame} - - -\section{Other Options} - -% --------------------------------------------- -\begin{frame}[fragile]{Object-Relation Mappers} - -\vfill -{\Large Systems for mapping Python objects to tables} - -\vfill -{\Large Saves you writing that glue code (and the SQL) } - -\vfill -{\Large Usually deal with mapping to variety of back-ends:\\ - -- test with SQLite, deploy with PostreSQL} - -\vfill -{\Large SQL Alchemy}\\ - -- \url{http://www.sqlalchemy.org/} - -\vfill -{\Large Django ORM}\\ -\url{https://docs.djangoproject.com/en/dev/topics/db/} - -\end{frame} - - -% --------------------------------------------- -\begin{frame}[fragile]{Object Databases} - -{\Large Directly store and retrieve Python Objects.} - -\vfill -{\Large Kind of like \verb|shelve|, but more flexible, and give you searching, etc.} - -\vfill -{\Large ZODB:}\\ -(\url{http://www.zodb.org/}) - -\vfill -{\Large Durus:}\\ -(\url{https://www.mems-exchange.org/software/DurusWorks/}) - -\end{frame} - -% --------------------------------------------- -\begin{frame}[fragile]{NoSQL} - -{\Large Map-Reduce, etc.} - -\vfill -{\Large....Big deal for "Big Data": Amazon, Google, etc.} - -\vfill -{\Large Document-Oriented Storage} - -{\large -\begin{itemize} - \item MongoDB (BSON interface, JSON documents) - \item CouchDB (Apache): - \begin{itemize} - \item JSON documents - \item Javascript querying (MapReduce) - \item HTTP API - \end{itemize} -\end{itemize} -} - -\end{frame} - -%------------------------------- -\begin{frame}{Evaluations} - -{\LARGE I need to submit evaluations to UW} - -\vfill -{\LARGE We'll so that now -- then the last LAB} - -\end{frame} - - -\begin{frame}[fragile]{LAB} - -\begin{verbatim} -# load with: -from add_book_data import AddressBook -\end{verbatim} - -\begin{itemize} - \item Write a module that saves the data in a dbm datbase\\ - --- and reads it back in - \item Write a module that saves the data in an SQLItE datbase\\ - --- and reads it back in - --- helps to know SQL here... -\end{itemize} - -\end{frame} - -%------------------------------- -\begin{frame}{Homework} - -\vfill -{\Large Send me a copy of your project: due next Sunday} - -\vfill -{\Large Keep learning about and using Python} -\vfill - -\end{frame} - - - - -\end{document} - - diff --git a/slides_sources/requirements.txt b/slides_sources/requirements.txt deleted file mode 100644 index 69243dbf..00000000 --- a/slides_sources/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -Jinja2==2.7.2 -MarkupSafe==0.19 -Pygments==1.6 -Sphinx==1.2.2 -docutils==0.11 -sphinx-rtd-theme==0.1.6 diff --git a/slides_sources/scss_sources/slides_custom.scss b/slides_sources/scss_sources/slides_custom.scss deleted file mode 100644 index 2d01f6d7..00000000 --- a/slides_sources/scss_sources/slides_custom.scss +++ /dev/null @@ -1,190 +0,0 @@ -$main-color: #515151; - -body { - -webkit-transition: opacity 200ms ease-in; - -webkit-transition-delay: 50ms; - -moz-transition: opacity 200ms ease-in 50ms; - -o-transition: opacity 200ms ease-in 50ms; - transition: opacity 200ms ease-in 50ms; -} -slides { - -webkit-transition: opacity 200ms ease-in; - -webkit-transition-delay: 50ms; - -moz-transition: opacity 200ms ease-in 50ms; - -o-transition: opacity 200ms ease-in 50ms; - transition: opacity 200ms ease-in 50ms; -} -slides > slide { - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} -.highlight-code slide.current pre > * { - opacity: 0.25; - -webkit-transition: opacity 0.1s ease-in; - -moz-transition: opacity 0.1s ease-in; - -o-transition: opacity 0.1s ease-in; - transition: opacity 0.1s ease-in; -} -.build > *, p.build { - transition: opacity 0.1s ease-in-out 0.1s; - -o-transition: opacity 0.1s ease-in-out 0.1s; - -moz-transition: opacity 0.1s ease-in-out 0.1s; - -webkit-transition: opacity 0.1s ease-in-out 0.1s; -} -.note { - -webkit-transition: all 0.1s ease-in-out; - -moz-transition: all 0.1s ease-in-out; - -o-transition: all 0.1s ease-in-out; - transition: all 0.1s ease-in-out; -} -.with-notes.popup .note { - -webkit-transition: opacity 100ms ease-in-out; - -moz-transition: opacity 100ms ease-in-out; - -o-transition: opacity 100ms ease-in-out; - transition: opacity 100ms ease-in-out; -} -.auto-fadein { - -webkit-transition: opacity 0.25s ease-in; - -webkit-transition-delay: 0.25s; - -moz-transition: opacity 0.25s ease-in 0.25s; - -o-transition: opacity 0.25s ease-in 0.25s; - transition: opacity 0.25s ease-in 0.25s; -} -aside.gdbar { - -webkit-transition: all 0.1s ease-out; - -webkit-transition-delay: 0.1s; - -moz-transition: all 0.1s ease-out 0.1s; - -o-transition: all 0.1s ease-out 0.1s; - transition: all 0.1s ease-out 0.1s; - /* Better to transition only on background-size, but not sure how to do that with the mixin. */ -} - -em { - font-style: italic; -} - -strong { - font-weight: bold; -} - -hgroup { - .docutils { - &.literal { - font-family: 'Droid Sans Mono', 'Courier New', monospace; - } - } -} - -article { - .center { - text-align: center; - margin-top: 20%; - } - .centered { - text-align: center; - } - .left { - text-align: left; - } - .large { - font-weight: bold; - font-size: 65px; - line-height: 65px; - } - .mlarge { - font-weight: bold; - font-size: 55px; - line-height: 55px; - } - .medium { - font-weight: bold; - font-size: 45px; - line-height: 45px; - } - .credit { - font-size: 75%; - text-align: left; - } - .line-block { - .line { - font-size: inherit; - } - } - dl { - margin-bottom: 10em; - dt { - font-weight: bold; - margin-bottom: .25em; - } - dd { - padding-left: 1em; - margin-bottom: .5em; - } - } - .docutils { - &.literal { - font-family: 'Droid Sans Mono', 'Courier New', monospace; - } - } - .toctree-wrapper { - li { - a { - text-decoration: none; - border-bottom: none; - } - } - } - table.docutils { - tr { - td { - vertical-align: top; - } - } - } -} - -.level-1 { - h1 { - font-size: 65px; - line-height: 1.4; - letter-spacing: -3px; - color: $main-color; - } - article { - text-align: center; - img { - margin-top: 10px; - } - } -} - -.level-2 { - h2 { - position: static; - border-bottom: 1px solid $main-color; - border-top: 1px solid $main-color; - padding: 5px 0px; - color: $main-color; - - } - article { - text-align: center; - } -} - -.level-3 { - h3 { - position: static; - border-bottom: 1px solid $main-color; - color: $main-color; - font-size: 40px; - height: 45px; - line-height: 45px; - font-weight: bold; - } - article { - text-align: left; - } -} diff --git a/slides_sources/source/_templates/end_slide.html b/slides_sources/source/_templates/end_slide.html deleted file mode 100644 index 5d234476..00000000 --- a/slides_sources/source/_templates/end_slide.html +++ /dev/null @@ -1,8 +0,0 @@ - -
        -

        Thank You!

        -
        -

        - -

        -
        diff --git a/slides_sources/source/_templates/title_slide.html b/slides_sources/source/_templates/title_slide.html deleted file mode 100644 index f88023ee..00000000 --- a/slides_sources/source/_templates/title_slide.html +++ /dev/null @@ -1,8 +0,0 @@ - - -
        -

        -

        -

        -
        -
        diff --git a/slides_sources/source/conf.py b/slides_sources/source/conf.py deleted file mode 100644 index 10d71972..00000000 --- a/slides_sources/source/conf.py +++ /dev/null @@ -1,389 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Intro To Python build configuration file, created by -# sphinx-quickstart on Wed Apr 2 18:42:06 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import sphinx_rtd_theme - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.pngmath', - 'sphinx.ext.ifconfig', - 'IPython.sphinxext.ipython_console_highlighting', - 'IPython.sphinxext.ipython_directive', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Introduction To Python' -copyright = u'2014, Christopher Barker, Cris Ewing, ' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '1.3' -# The full version, including alpha/beta/rc tags. -release = '1.3' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'colorful' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'sphinx_rtd_theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'IntroToPythonDoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'IntroToPython.tex', u'Intro To Python Documentation', - u'Christopher Barker', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'Intro to Python', u'Intro to Python Documentation', - [u'Christopher Barker'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'IntroToPython', u'Intro to Python Documentation', - u'Christopher Barker', 'IntroToPython', 'Class materials for Intro to Python class', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - -# -- Hieroglyph Slide Configuration ------------ - -extensions += [ - 'hieroglyph', -] - -slide_title = "Intro to Python" -slide_theme = 'slides2' -slide_levels = 3 - -# Place custom static assets in the _static directory and uncomment -# the following lines to include them - -slide_theme_options = { - 'subtitle': 'Fundamentals of Python Programming', - 'custom_css': 'custom.css', - # 'custom_js': 'custom.js', - 'presenters': [ - { - 'name': u'Christopher Barker', - 'email': u'PythonCHB@gmail.com', - 'github': u'https://github.com/PythonCHB', - 'company': u'UW Prof. and Continuing Education Program' - }, - # { - # 'name': u'Dan Hable', - # 'email': u'dhable@gmail.com', - # # 'twitter': '@crisewing', - # # 'www': 'http://crisewing.com', - # 'github': u'http://github.com/dhable', - # 'company': u'' - # }, - # { - # 'name': 'Cris Ewing', - # 'twitter': '@crisewing', - # 'www': 'http://crisewing.com', - # 'github': 'http://github.com/cewing', - # 'company': 'Cris Ewing, Developer LLC' - # }, - ] -} - -# ---------------------------------------------- - - - -# -- Options for Epub output ---------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = u'Intro To Python' -epub_author = u'Christopher Barker' -epub_publisher = u'Christopher Barker' -epub_copyright = u'2014, Christopher Barker, Cris Ewing ' - -# The basename for the epub file. It defaults to the project name. -#epub_basename = u'Foundations 2: Python' - -# The HTML theme for the epub output. Since the default themes are not optimized -# for small screen space, using the same theme for HTML and epub output is -# usually not wise. This defaults to 'epub', a theme designed to save visual -# space. -#epub_theme = 'epub' - -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# A sequence of (type, uri, title) tuples for the guide element of content.opf. -#epub_guide = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - -# Choose between 'default' and 'includehidden'. -#epub_tocscope = 'default' - -# Fix unsupported image types using the PIL. -#epub_fix_images = False - -# Scale large images. -#epub_max_image_width = 0 - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#epub_show_urls = 'inline' - -# If false, no index is generated. -#epub_use_index = True - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/slides_sources/source/homework/sherlock_small.txt b/slides_sources/source/homework/sherlock_small.txt deleted file mode 100644 index 992a29b1..00000000 --- a/slides_sources/source/homework/sherlock_small.txt +++ /dev/null @@ -1,16 +0,0 @@ -One night--it was on the twentieth of March, 1888--I was -returning from a journey to a patient (for I had now returned to -civil practice), when my way led me through Baker Street. As I -passed the well-remembered door, which must always be associated -in my mind with my wooing, and with the dark incidents of the -Study in Scarlet, I was seized with a keen desire to see Holmes -again, and to know how he was employing his extraordinary powers. -His rooms were brilliantly lit, and, even as I looked up, I saw -his tall, spare figure pass twice in a dark silhouette against -the blind. He was pacing the room swiftly, eagerly, with his head -sunk upon his chest and his hands clasped behind him. To me, who -knew his every mood and habit, his attitude and manner told their -own story. He was at work again. He had risen out of his -drug-created dreams and was hot upon the scent of some new -problem. I rang the bell and was shown up to the chamber which -had formerly been in part my own. diff --git a/slides_sources/source/session04.rst b/slides_sources/source/session04.rst deleted file mode 100644 index 75c790af..00000000 --- a/slides_sources/source/session04.rst +++ /dev/null @@ -1,1162 +0,0 @@ -.. Foundations 2: Python slides file, created by - Chris Barker: May 12, 2014. - -******************************************************* -Session Four: Dictionaries, Sets, Exceptions, and Files -******************************************************* - - - -================ -Review/Questions -================ - -Review of Previous Classes --------------------------- - - * Sequences - - - Slicing - - Lists - - Tuples - - tuple vs lists - which to use? - - * interating - - - for - - while - - - break and continue - - - else with loops - -Any questions? - -.. nextslide:: - -A couple other nifty utilties with for loops: - -**tuple unpacking:** - -remember this? - -.. code-block:: python - - x, y = 3, 4 - -You can do that in a for loop, also: - -.. code-block:: ipython - - In [4]: l = [(1, 2), (3, 4), (5, 6)] - - In [5]: for i, j in l: - print "i:%i, j:%i"%(i, j) - - i:1, j:2 - i:3, j:4 - i:5, j:6 - -Looping through two loops at once: ----------------------------------- - -**zip:** - -.. code-block:: ipython - - In [10]: l1 = [1, 2, 3] - - In [11]: l2 = [3, 4, 5] - - In [12]: for i, j in zip(l1, l2): - ....: print "i:%i, j:%i"%(i, j) - ....: - i:1, j:3 - i:2, j:4 - i:3, j:5 - - - -Homework comments ------------------ - -Building up a long string. - -The obvious thing to do is something like:: - - msg = u"" - for piece in list_of_stuff: - msg += piece - -But: strings are immutable -- python needs to create a new string each time you add a piece -- not efficient:: - - msg = [] - for piece in list_of_stuff: - msg.append(piece) - u" ".join(msg) - -appending to lists is efficient -- and so is the join() method of strings. - - -.. nextslide:: - -What is ``assert`` for? - -Testing -- NOT for issues expected to happen operationally:: - - assert m >= 0 - -in operational code should be:: - - if m < 0: - raise ValueError - -I'll cover Exceptions later this class... - -(Asserts get ignored if optimization is turned on!) - - -================= -A little warm up -================= - -Fun with strings ------------------- - -* Rewrite: ``the first 3 numbers are: %i, %i, %i"%(1,2,3)`` - - - for an arbitrary number of numbers... - -* Write a format string that will take: - - - ``( 2, 123.4567, 10000)`` - - - and produce: - - - `` "file_002 : 123.46, 1e+04" `` - -===================== -Dictionaries and Sets -===================== - -Dictionary ----------- -Python calls it a ``dict`` - -Other languages call it: - - * dictionary - * associative array - * map - * hash table - * hash - * key-value pair - - -Dictionary Constructors ------------------------ -.. code-block:: python - - >>> {'key1': 3, 'key2': 5} - {'key1': 3, 'key2': 5} - - >>> dict([('key1', 3),('key2', 5)]) - {'key1': 3, 'key2': 5} - - >>> dict(key1=3, key2= 5) - {'key1': 3, 'key2': 5} - - >>> d = {} - >>> d['key1'] = 3 - >>> d['key2'] = 5 - >>> d - {'key1': 3, 'key2': 5} - -Dictionary Indexing -------------------- -:: - - >>> d = {'name': 'Brian', 'score': 42} - - >>> d['score'] - 42 - - >>> d = {1: 'one', 0: 'zero'} - - >>> d[0] - 'zero' - - >>> d['non-existing key'] - Traceback (most recent call last): - File "", line 1, in - KeyError: 'non-existing key' - - -.. nextslide:: - -Keys can be any immutable: - - * number - * string - * tuple - -.. code-block:: ipython - - In [325]: d[3] = 'string' - In [326]: d[3.14] = 'pi' - In [327]: d['pi'] = 3.14 - In [328]: d[ (1,2,3) ] = 'a tuple key' - In [329]: d[ [1,2,3] ] = 'a list key' - TypeError: unhashable type: 'list' - - -Actually -- any "hashable" type. - - -.. nextslide:: Hashing - -Hash functions convert arbitrarily large data to a small proxy (usually int) - -Always return the same proxy for the same input - -MD5, SHA, etc - -Dictionaries hash the key to an integer proxy and use it to find the key and value. - -Key lookup is efficient because the hash function leads directly to a bucket with very few keys (often just one) - -What would happen if the proxy changed after storing a key? - -Hashability requires immutability - -Key lookup is very efficient - -Same average time regardless of size - - -.. nextslide:: Dictionary indexing - - -Note: Python name look-ups are implemented with dict -- it's highly optimized - -Key to value: - - * lookup is one way - -Value to key: - - * requires visiting the whole dict - -If you need to check dict values often, create another dict or set - -(up to you to keep them in sync) - - -Dictionary Ordering (not) -------------------------- - - -Dictionaries have no defined order - -.. code-block:: ipython - - In [352]: d = {'one':1, 'two':2, 'three':3} - In [353]: d - Out[353]: {'one': 1, 'three': 3, 'two': 2} - In [354]: d.keys() - Out[354]: ['three', 'two', 'one'] - -Dictionary Iterating --------------------- - -``for`` iterates over the keys - -.. code-block:: ipython - - In [15]: d = {'name': 'Brian', 'score': 42} - - In [16]: for x in d: - print x - ....: - score - name - - -(note the different order...) - -dict keys and values --------------------- - -.. code-block:: ipython - - In [20]: d = {'name': 'Brian', 'score': 42} - - In [21]: d.keys() - Out[21]: ['score', 'name'] - - In [22]: d.values() - Out[22]: [42, 'Brian'] - - In [23]: d.items() - Out[23]: [('score', 42), ('name', 'Brian')] - - -dict keys and values --------------------- - -Iterating on everything - -.. code-block:: ipython - - In [26]: d = {'name': 'Brian', 'score': 42} - - In [27]: for k, v in d.items(): - print "%s: %s" % (k,v) - ....: - score: 42 - name: Brian - - -Dictionary Performance ------------------------ - - * indexing is fast and constant time: O(1) - - * ``x in s`` constant time: O(1) - - * visiting all is proportional to n: O(n) - - * inserting is constant time: O(1) - - * deleting is constant time: O(1) - - - http://wiki.python.org/moin/TimeComplexity - - -Other dict operations: ----------------------- - -See them all here: - -https://docs.python.org/2/library/stdtypes.html#mapping-types-dict - -Is it in there? - -.. code-block:: ipython - - In [5]: d - Out[5]: {'that': 7, 'this': 5} - - In [6]: 'that' in d - Out[6]: True - - In [7]: 'this' not in d - Out[7]: False - -Containment is on the keys. - -.. nextslide:: - -Getting something: (like indexing) - -.. code-block:: ipython - - In [9]: d.get('this') - Out[9]: 5 - -But you can specify a default - -.. code-block:: ipython - - In [11]: d.get(u'something', u'a default') - Out[11]: u'a default' - -Never raises an Exception (default default is None) - -.. nextslide:: - -iterating - -.. code-block:: ipython - - In [13]: for item in d.iteritems(): - ....: print item - ....: - ('this', 5) - ('that', 7) - In [15]: for key in d.iterkeys(): - print key - ....: - this - that - In [16]: for val in d.itervalues(): - print val - ....: - 5 - 7 - -the ``iter*`` methods don't actually create the lists. - -.. nextslide:: - -"Popping": getting the value while removing it - -pop out a particular key - -.. code-block:: ipython - - In [19]: d.pop('this') - Out[19]: 5 - - In [20]: d - Out[20]: {'that': 7} - -pop out an arbitrary key, value pair - -.. code-block:: ipython - - In [23]: d.popitem() - Out[23]: ('that', 7) - - In [24]: d - Out[24]: {} - -.. nextslide:: - -This one is handy: - -``setdefault(key[, default])`` - -gets the value if it's there, sets it if it's not - -.. code-block:: ipython - - In [27]: d.setdefault(u'something', u'a value') - Out[27]: u'a value' - - In [28]: d - Out[28]: {u'something': u'a value'} - - In [29]: d.setdefault(u'something', u'a value') - Out[29]: u'a value' - - In [30]: d - Out[30]: {u'something': u'a value'} - -.. nextslide:: - -dict View objects: - -Like ``keys()``, ``values()``, ``items()``, but maintain a link to the original dict - -.. code-block:: ipython - - In [47]: d - Out[47]: {u'something': u'a value'} - - In [48]: item_view = d.viewitems() - - In [49]: d['something else'] = u'another value' - - In [50]: item_view - Out[50]: dict_items([('something else', u'another value'), (u'something', u'a value')]) - - - -Sets ------ - -``set`` is an unordered collection of distinct values - -Essentially a dict with only keys - -Set Constructors - -.. code-block:: ipython - - >>> set() - set([]) - - >>> set([1, 2, 3]) - set([1, 2, 3]) - - >>> {1, 2, 3} - set([1, 2, 3]) - - >>> s = set() - - >>> s.update([1, 2, 3]) - >>> s - set([1, 2, 3]) - - -Set Properties ---------------- - -``Set`` members must be hashable - -Like dictionary keys -- and for same reason (efficient lookup) - -No indexing (unordered) - -.. code-block:: ipython - - >>> s[1] - Traceback (most recent call last): - File "", line 1, in - TypeError: 'set' object does not support indexing - - -Set Methods ------------ - -.. code-block:: ipython - - >> s = set([1]) - >>> s.pop() # an arbitrary member - 1 - >>> s.pop() - Traceback (most recent call last): - File "", line 1, in - KeyError: 'pop from an empty set' - >>> s = set([1, 2, 3]) - >>> s.remove(2) - >>> s.remove(2) - Traceback (most recent call last): - File "", line 1, in - KeyError: 2 - -.. nextslide:: - -All the "set" operations from math class... - -.. code-block:: python - - s.isdisjoint(other) - - s.issubset(other) - - s.union(other, ...) - - s.intersection(other, ...) - - s.difference(other, ...) - - s.symmetric_difference( other, ...) - -Frozen Set ----------- - -Another kind of set: ``frozenset`` - -immutable -- for use as a key in a dict -(or another set...) - -.. code-block:: python - - >>> fs = frozenset((3,8,5)) - >>> fs.add(9) - Traceback (most recent call last): - File "", line 1, in - AttributeError: 'frozenset' object has no attribute 'add' - - -========== -Exceptions -========== - -Exceptions ----------- - -Another Branching structure: - -.. code-block:: python - - try: - do_something() - f = open('missing.txt') - process(f) # never called if file missing - except IOError: - print "couldn't open missing.txt" - -Exceptions ----------- -Never Do this: - -.. code-block:: python - - try: - do_something() - f = open('missing.txt') - process(f) # never called if file missing - except: - print "couldn't open missing.txt" - - -Exceptions ----------- - -Use Exceptions, rather than your own tests: - -Don't do this: - -.. code-block:: python - - do_something() - if os.path.exists('missing.txt'): - f = open('missing.txt') - process(f) # never called if file missing - -It will almost always work -- but the almost will drive you crazy - -.. nextslide:: - -Example from homework - -.. code-block:: python - - if num_in.isdigit(): - num_in = int(num_in) - -but -- ``int(num_in)`` will only work if the string can be converted to an integer. - -So you can do - -.. code-block:: python - - try: - num_in = int(num_in) - except ValueError: - print u"Input must be an integer, try again." - -Or let the Exception be raised.... - - -.. nextslide:: EAFP - - -"it's Easier to Ask Forgiveness than Permission" - - -- Grace Hopper - - -http://www.youtube.com/watch?v=AZDWveIdqjY - -(Pycon talk by Alex Martelli) - -.. nextslide:: Do you catch all Exceptions? - -For simple scripts, let exceptions happen. - -Only handle the exception if the code can and will do something about it. - -(much better debugging info when an error does occur) - - -Exceptions -- finally ---------------------- - -.. code-block:: python - - try: - do_something() - f = open('missing.txt') - process(f) # never called if file missing - except IOError: - print "couldn't open missing.txt" - finally: - do_some_clean-up - -The ``finally:`` clause will always run - - -Exceptions -- else -------------------- - -.. code-block:: python - - try: - do_something() - f = open('missing.txt') - except IOError: - print "couldn't open missing.txt" - else: - process(f) # only called if there was no exception - -Advantage: - -you know where the Exception came from - -Exceptions -- using them ------------------------- - -.. code-block:: python - - try: - do_something() - f = open('missing.txt') - except IOError as the_error: - print the_error - the_error.extra_info = "some more information" - raise - - -Particularly useful if you catch more than one exception: - -.. code-block:: python - - except (IOError, BufferError, OSError) as the_error: - do_something_with (the_error) - - -Raising Exceptions -------------------- - -.. code-block:: python - - def divide(a,b): - if b == 0: - raise ZeroDivisionError("b can not be zero") - else: - return a / b - - -when you call it: - -.. code-block:: ipython - - In [515]: divide (12,0) - ZeroDivisionError: b can not be zero - - -Built in Exceptions -------------------- - -You can create your own custom exceptions - -But... - -.. code-block:: python - - exp = \ - [name for name in dir(__builtin__) if "Error" in name] - len(exp) - 32 - - -For the most part, you can/should use a built in one - -.. nextslide:: - -Choose the best match you can for the built in Exception you raise. - -Example (for last week's ackerman homework):: - - if (not isinstance(m, int)) or (not isinstance(n, int)): - raise ValueError - -Is it the *value* or the input the problem here? - -Nope: the *type* is the problem:: - - if (not isinstance(m, int)) or (not isinstance(n, int)): - raise TypeError - -but should you be checking type anyway? (EAFP) - - -======================== -File Reading and Writing -======================== - -Files ------ - -Text Files - -.. code-block:: python - - import io - f = io.open('secrets.txt', codec='utf-8') - secret_data = f.read() - f.close() - -``secret_data`` is a (unicode) string - -``codec`` defaults to ``sys.getdefaultencoding()`` -- often NOT what you want. - -(There is also the regular ``open()`` built in, but it won't handle Unicode for you...) - -.. nextslide:: - -Binary Files - -.. code-block:: python - - f = io.open('secrets.bin', 'rb') - secret_data = f.read() - f.close() - -``secret_data`` is a byte string - -(with arbitrary bytes in it -- well, not arbitrary -- whatever is in the file.) - -(See the ``struct`` module to unpack binary data ) - - -.. nextslide:: - - -File Opening Modes - -.. code-block:: python - - f = io.open('secrets.txt', [mode]) - 'r', 'w', 'a' - 'rb', 'wb', 'ab' - r+, w+, a+ - r+b, w+b, a+b - U - U+ - -These follow the Unix conventions, and aren't all that well documented on the Python docs. But these BSD docs make it pretty clear: - -http://www.manpagez.com/man/3/fopen/ - -**Gotcha** -- 'w' modes always clear the file - -.. nextslide:: Text File Notes - -Text is default - - * Newlines are translated: ``\r\n -> \n`` - * -- reading and writing! - * Use \*nix-style in your code: ``\n`` - * ``io.open()`` returns various "stream" objects -- but they act like file objects. - * In text mode, io.open() defaults to "Universal" newline mode. - - -Gotcha: - - * no difference between text and binary on \*nix - * breaks on Windows - - -.. nextslide:: Other parameters to ``io.open()``: - -``io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True)`` - - * ``file`` is generally a file name or full path - - * ``mode`` is the mode for opening: 'r', 'w', etc. - - * ``buffering`` controls the buffering mode (0 for no buffering) - - * ``encoding`` sets the unicode encoding -- only for text files -- when set, you can ONLY write unicode object to the file. - - * ``errors`` sets the encoding error mode: 'strict', 'ignore', 'replace',... - - * ``newline`` controls Universal Newline mode: lets you write DOS-type files on \*nix, for instance (text mode only). - - * ``closedfd`` controls close() behavior if a file descriptor, rather than a name is passed in (advanced usage!) - -(https://docs.python.org/2/library/io.html?highlight=io.open#io.open) - - -File Reading ------------- - -Reading part of a file - -.. code-block:: python - - header_size = 4096 - f = open('secrets.txt') - secret_header = f.read(header_size) - secret_rest = f.read() - f.close() - -.. nextslide:: - - -Common Idioms - -.. code-block:: python - - for line in io.open('secrets.txt'): - print line - -(the file object is an iterator!) - -.. code-block:: python - - f = io.open('secrets.txt') - while True: - line = f.readline() - if not line: - break - do_something_with_line() - - -File Writing ------------- - -.. code-block:: python - - outfile = io.open('output.txt', 'w') - for i in range(10): - outfile.write("this is line: %i\n"%i) - - -File Methods ------------- - -Commonly Used Methods - -.. code-block:: python - - f.read() f.readline() f.readlines() - - f.write(str) f.writelines(seq) - - f.seek(offset) f.tell() - - f.flush() - - f.close() - - -File Like Objects ------------------ - - -Many classes implement the file interface: - - * loggers - * ``sys.stdout`` - * ``urllib.open()`` - * pipes, subprocesses - * StringIO - -https://docs.python.org/2/library/stdtypes.html#file-objects - -StringIO --------- - -.. code-block:: python - - In [417]: import StringIO - In [420]: f = StringIO.StringIO() - In [421]: f.write(u"somestuff") - In [422]: f.seek(0) - In [423]: f.read() - Out[423]: 'somestuff' - -(handy for testing file handling code...) - - -===================== -Paths and Directories -===================== - -Paths ------ - -Paths are generally handled with simple strings (or Unicode strings) - -Relative paths: - -.. code-block:: python - - u'secret.txt' - u'./secret.txt' - -Absolute paths: - -.. code-block:: python - - u'/home/chris/secret.txt' - - -Either work with ``open()`` , etc. - -(working directory only makes sense with command-line programs...) - -os module ----------- - -.. code-block:: python - - os.getcwd() -- os.getcwdu() (u for Unicode) - chdir(path) - os.path.abspath() - os.path.relpath() - - -.. nextslide:: os.path module - -.. code-block:: python - - os.path.split() - os.path.splitext() - os.path.basename() - os.path.dirname() - os.path.join() - - -(all platform independent) - -.. nextslide:: directories - -.. code-block:: python - - os.listdir() - os.mkdir() - os.walk() - -(higher level stuff in ``shutil`` module) - -pathlib -------- - -``pathlib`` is a new package for handling paths in an OO way: - -http://pathlib.readthedocs.org/en/pep428/ - -It is now part of the Python3 standard library, and has been back-ported for use with Python2: - -.. code-block:: bash - - $ pip install pathlib - -All the stuff in os.path and more: - -.. code-block:: ipython - - In [64]: import pathlib - In [65]: pth = pathlib.Path('./') - In [66]: pth.is_dir() - Out[66]: True - In [67]: pth.absolute() - Out[67]: PosixPath('/Users/Chris/PythonStuff/CodeFellowsClass/sea-f2-python-sept14/Examples/Session04') - In [68]: for f in pth.iterdir(): - print f - junk2.txt - junkfile.txt - ... - -========= -Homework -========= - -Recommended Reading: ---------------------- - * Dive Into Python: Chapt. 13,14 - * Unicode: http://www.joelonsoftware.com/articles/Unicode.html - -Assignments: -------------- - - * dict/sets lab - * coding kata: trigrams - * Exceptions - * Update mailroom with dicts. - - -Dictionaries and Sets ---------------------- - -1. - -* Create a dictionary containing "name", "city", and "cake" for "Chris" from "Seattle" who likes "Chocolate". - -* Display the dictionary. - -* Delete the entry for "cake". - -* Display the dictionary. - -* Add an entry for "fruit" with "Mango" and display the dictionary. - - - Display the dictionary keys. - - Display the dictionary values. - - Display whether or not "cake" is a key in the dictionary (i.e. False) (now). - - Display whether or not "Mango" is a value in the dictionary. - -.. nextslide:: - -2. - -* Using the dict constructor and zip, build a dictionary of numbers from zero to fifteen and the hexadecimal equivalent (string is fine). - -3. - -* Using the dictionary from item 1: Make a dictionary using the same keys but with the number of 'a's in each value. - -.. nextslide:: sets - -4. - -* Create sets s2, s3 and s4 that contain numbers from zero through twenty, divisible 2, 3 and 4. - -* Display the sets. - -* Display if s3 is a subset of s2 (False) - -* and if s4 is a subset of s2 (True). - -5. - -* Create a set with the letters in 'Python' and add 'i' to the set. - -* Create a frozenset with the letters in 'marathon' - -* display the union and intersection of the two sets. - - -Text and files and dicts, and... ---------------------------------- - - * Coding Kata 14 - Dave Thomas - - http://codekata.com/kata/kata14-tom-swift-under-the-milkwood/ - - and in this doc: - - http://codefellows.github.io/sea-c15-python/supplements/kata_fourteen.html - - * Use The Adventures of Sherlock Holmes as input: - - http://codefellows.github.io/sea-c15-python/_downloads/sherlock.txt - - * This is intentionally open-ended and underspecified. There are many interesting decisions to make. - - * Experiment with different lengths for the lookup key. (3 words, 4 words, 3 letters, etc) - -Exceptions ------------ - -Improving ``raw_input`` - -* The ``raw_input()`` function can generate two exceptions: ``EOFError`` or ``KeyboardInterrupt`` on end-of-file(EOF) or canceled input. - -* Create a wrapper function, perhaps ``safe_input()`` that returns ``None`` rather rather than raising these exceptions, when the user enters ``^C`` for Keyboard Interrupt, or ``^D`` (``^Z`` on Windows) for End Of File. - -* Update your mailroom program to use exceptions (and IBAFP) to handle malformed numeric input - - -Paths and File Processing --------------------------- - - * write a program which prints the full path to all files in the current directory, one per line - - * write a program which copies a file from a source, to a destination (without using shutil, or the OS copy command) - - * update mailroom from last weeks homework to: - - - use dicts where appropriate - - write a full set of letters to everyone to individual files on disk - - see if you can use a dict to switch between the users selections - - Try to use a dict and the .format() method to do the letter as one big template -- rather than building up a big string in parts. - diff --git a/slides_sources/source/session05.rst b/slides_sources/source/session05.rst deleted file mode 100644 index c8cffe56..00000000 --- a/slides_sources/source/session05.rst +++ /dev/null @@ -1,1031 +0,0 @@ - -.. Foundations 2: Python slides file, created by - hieroglyph-quickstart on Wed Apr 2 18:42:06 2014. - - -******************************************************************************************************** -Session Five: Advanced Argument passing, List and Dict Comprehensions, Lambda and Functional programming -******************************************************************************************************** - - -================ -Review/Questions -================ - -Review of Previous Class ------------------------- - - * Dictionaries - * Exceptions - * Files, etc. - - -Homework review ---------------- - -Homework Questions? - -My Solutions to the dict/set lab, and some others in the class repo in: ``Solutions`` - -A few tidbits: - -.. nextslide:: Sorting stuff in dictionaries: - -dicts aren't sorted, so what if you want to do something in a sorted way? - -The "old" way: - -.. code-block:: python - - keys = d.keys() - keys.sort() - for key in keys: - ... - -.. code-block:: python - - collections.OrderedDict - - sorted() - -(demo) - -========================= -Advanced Argument Passing -========================= - -Keyword arguments ------------------ - -When defining a function, you can specify only what you need -- in any order - -.. code-block:: ipython - - In [151]: def fun(x,y=0,z=0): - print x,y,z - .....: - In [152]: fun(1,2,3) - 1 2 3 - In [153]: fun(1, z=3) - 1 0 3 - In [154]: fun(1, z=3, y=2) - 1 2 3 - - -.. nextslide:: - - -A Common Idiom: - -.. code-block:: python - - def fun(x, y=None): - if y is None: - do_something_different - go_on_here - - - -.. nextslide:: - -Can set defaults to variables - -.. code-block:: ipython - - In [156]: y = 4 - In [157]: def fun(x=y): - print "x is:", x - .....: - In [158]: fun() - x is: 4 - - -.. nextslide:: - -Defaults are evaluated when the function is defined - -.. code-block:: ipython - - In [156]: y = 4 - In [157]: def fun(x=y): - print "x is:", x - .....: - In [158]: fun() - x is: 4 - In [159]: y = 6 - In [160]: fun() - x is: 4 - - - -Function arguments in variables -------------------------------- - -function arguments are really just - -* a tuple (positional arguments) -* a dict (keyword arguments) - -.. code-block:: python - - def f(x, y, w=0, h=0): - print "position: %s, %s -- shape: %s, %s"%(x, y, w, h) - - position = (3,4) - size = {'h': 10, 'w': 20} - - >>> f( *position, **size) - position: 3, 4 -- shape: 20, 10 - - - -Function parameters in variables --------------------------------- - -You can also pull the parameters out in the function as a tuple and a dict: - -.. code-block:: ipython - - def f(*args, **kwargs): - print "the positional arguments are:", args - print "the keyword arguments are:", kwargs - - In [389]: f(2, 3, this=5, that=7) - the positional arguments are: (2, 3) - the keyword arguments are: {'this': 5, 'that': 7} - -Passing a dict to the ``string.format()`` method ------------------------------------------------- - -Now that you know that keyword args are really a dict, you can do this nifty trick: - -The ``format`` method takes keyword arguments: - -.. code-block:: ipython - - In [24]: u"My name is {first} {last}".format(last=u"Barker", first=u"Chris") - Out[24]: u'My name is Chris Barker' - -Build a dict of the keys and values: - -.. code-block:: ipython - - In [25]: d = {u"last":u"Barker", u"first":u"Chris"} - -And pass to ``format()``with ``**`` - -.. code-block:: ipython - - In [26]: u"My name is {first} {last}".format(**d) - Out[26]: u'My name is Chris Barker' - - - - -LAB ---- - -Let's do this right now: - -keyword arguments - -* Write a function that has four optional parameters (with defaults): - - - foreground_color - - background_color - - link_color - - visited_link_color - -* Have it print the colors (use strings for the colors) -* Call it with a couple different parameters set -* Have it pull the parameters out with ``*args, **kwargs`` - -===================================== -A bit more on mutability (and copies) -===================================== - -mutable objects ----------------- - -We've talked about this: mutable objects can have their contents changed in place. - -Immutable objects can not. - -This has implications when you have a container with mutable objects in it: - -.. code-block:: ipython - - In [28]: list1 = [ [1,2,3], ['a','b'] ] - -one way to make a copy of a list: - -.. code-block:: ipython - - In [29]: list2 = list1[:] - - In [30]: list2 is list1 - Out[30]: False - -they are different lists. - -.. nextslide:: - -What if we set an element to a new value? - -.. code-block:: ipython - - In [31]: list1[0] = [5,6,7] - - In [32]: list1 - Out[32]: [[5, 6, 7], ['a', 'b']] - - In [33]: list2 - Out[33]: [[1, 2, 3], ['a', 'b']] - -So they are independent. - -.. nextslide:: - -But what if we mutate an element? - -.. code-block:: ipython - - In [34]: list1[1].append('c') - - In [35]: list1 - Out[35]: [[5, 6, 7], ['a', 'b', 'c']] - - In [36]: list2 - Out[36]: [[1, 2, 3], ['a', 'b', 'c']] - -uuh oh! mutating an element in one list mutated the one in the other list. - -.. nextslide:: - -Why is that? - -.. code-block:: ipython - - In [38]: list1[1] is list2[1] - Out[38]: True - -The elements are the same object! - -This is known as a "shallow" copy -- Python doesn't want to copy more than it needs to, so in this case, it makes a new list, but does not make copies of the contents. - -Same for dicts (and any container type) - -If the elements are immutable, it doesn't really make a differnce -- but be very careful with mutable elements. - - -The copy module --------------------- - -most objects have a way to make copies (``dict.copy()`` for instance). - -but if not, you can use the ``copy`` module to make a copy: - -.. code-block:: ipython - - In [39]: import copy - - In [40]: list3 = copy.copy(list2) - - In [41]: list3 - Out[41]: [[1, 2, 3], ['a', 'b', 'c']] - -This is also a shallow copy. - -.. nextslide:: - -But there is another option: - -.. code-block:: ipython - - In [3]: list1 - Out[3]: [[1, 2, 3], ['a', 'b', 'c']] - - In [4]: list2 = copy.deepcopy(list1) - - In [5]: list1[0].append(4) - - In [6]: list1 - Out[6]: [[1, 2, 3, 4], ['a', 'b', 'c']] - - In [7]: list2 - Out[7]: [[1, 2, 3], ['a', 'b', 'c']] - -``deepcopy`` recurses through the object, making copies of everything as it goes. - -.. nextslide:: - - -I happened on this thread on stack overflow: - -http://stackoverflow.com/questions/3975376/understanding-dict-copy-shallow-or-deep - - -The OP is pretty confused -- can you sort it out? - -Make sure you understand the difference between a reference, a shallow copy, and a deep copy. - -Mutables as default arguments: ------------------------------- - -Another "gotcha" is using mutables as default arguments: - -.. code-block:: ipython - - In [11]: def fun(x, a=[]): - ....: a.append(x) - ....: print a - ....: - -This makes sense: maybe you'd pass in a list, but the default is an empty list. - -But: - -.. code-block:: ipython - - In [12]: fun(3) - [3] - - In [13]: fun(4) - [3, 4] - -Huh?! - -.. nextslide:: - -Remember that that default argument is defined when the function is created: there will be only one list, and every time the function is called, that same list is used. - - -The solution: - -The standard practice for such a mutable default argument: - -.. code-block:: ipython - - In [15]: def fun(x, a=None): - ....: if a is None: - ....: a = [] - ....: a.append(x) - ....: print a - In [16]: fun(3) - [3] - In [17]: fun(4) - [4] - -You get a new list every time the function is called - - -============================ -List and Dict Comprehensions -============================ - -List comprehensions -------------------- -A bit of functional programming - - -consider this common for loop structure: - -.. code-block:: python - - new_list = [] - for variable in a_list: - new_list.append(expression) - -This can be expressed with a single line using a "list comprehension" - -.. code-block:: python - - new_list = [expression for variable in a_list] - - -.. nextslide:: - - -What about nested for loops? - -.. code-block:: python - - new_list = [] - for var in a_list: - for var2 in a_list2: - new_list.append(expression) - -Can also be expressed in one line: - -.. code-block:: python - - new_list = [exp for var in a_list for var2 in a_list2] - -You get the "outer product", i.e. all combinations. - -(demo) - -.. nextslide:: - -But usually you at least have a conditional in the loop: - -.. code-block:: python - - new_list = [] - for variable in a_list: - if something_is_true: - new_list.append(expression) - -You can add a conditional to the comprehension: - -.. code-block:: python - - new_list = [expr for var in a_list if something_is_true] - - - -(demo) - -.. nextslide:: - -Examples: - -.. code-block:: ipython - - In [341]: [x**2 for x in range(3)] - Out[341]: [0, 1, 4] - - In [342]: [x+y for x in range(3) for y in range(5,7)] - Out[342]: [5, 6, 6, 7, 7, 8] - - In [343]: [x*2 for x in range(6) if not x%2] - Out[343]: [0, 4, 8] - - - -.. nextslide:: - -Remember this from last week? - -.. code-block:: python - - [name for name in dir(__builtin__) if "Error" in name] - ['ArithmeticError', - 'AssertionError', - 'AttributeError', - 'BufferError', - 'EOFError', - .... - - - -Set Comprehensions ------------------- - -You can do it with sets, too: - -.. code-block:: python - - new_set = { value for variable in a_sequence } - - -same as for loop: - -.. code-block:: python - - new_set = set() - for key in a_list: - new_set.add(value) - - - -.. nextslide:: - -Example: finding all the vowels in a string... - -.. code-block:: ipython - - In [19]: s = "a not very long string" - - In [20]: vowels = set('aeiou') - - In [21]: { let for let in s if let in vowels } - Out[21]: {'a', 'e', 'i', 'o'} - -Side note: why did I do ``set('aeiou')`` rather than just `aeiou` ? - - -Dict Comprehensions -------------------- - -Also with dictionaries - -.. code-block:: python - - new_dict = { key:value for variable in a_sequence} - - -same as for loop: - -.. code-block:: python - - new_dict = {} - for key in a_list: - new_dict[key] = value - - - -.. nextslide:: - -Example - -.. code-block:: ipython - - In [22]: { i: "this_%i"%i for i in range(5) } - Out[22]: {0: 'this_0', 1: 'this_1', 2: 'this_2', - 3: 'this_3', 4: 'this_4'} - - -(not as useful with the ``dict()`` constructor...) - - -=================== -Anonymous functions -=================== - -lambda ------- - -.. code-block:: ipython - - In [171]: f = lambda x, y: x+y - In [172]: f(2,3) - Out[172]: 5 - -Content can only be an expression -- not a statement - -Anyone remember what the difference is? - -Called "Anonymous": it doesn't need a name. - -.. nextslide:: - -It's a python object, it can be stored in a list or other container - -.. code-block:: ipython - - In [7]: l = [lambda x, y: x+y] - In [8]: type(l[0]) - Out[8]: function - - -And you can call it: - -.. code-block:: ipython - - In [9]: l[0](3,4) - Out[9]: 7 - - -Functions as first class objects ---------------------------------- - -You can do that with "regular" functions too: - -.. code-block:: ipython - - In [12]: def fun(x,y): - ....: return x+y - ....: - In [13]: l = [fun] - In [14]: type(l[0]) - Out[14]: function - In [15]: l[0](3,4) - Out[15]: 7 - - - -====================== -Functional Programming -====================== - -map ---- - -``map`` "maps" a function onto a sequence of objects -- It applies the function to each item in the list, returning another list - - -.. code-block:: ipython - - In [23]: l = [2, 5, 7, 12, 6, 4] - In [24]: def fun(x): - return x*2 + 10 - In [25]: map(fun, l) - Out[25]: [14, 20, 24, 34, 22, 18] - - -But if it's a small function, and you only need it once: - -.. code-block:: ipython - - In [26]: map(lambda x: x*2 + 10, l) - Out[26]: [14, 20, 24, 34, 22, 18] - - -filter ------- - -``filter`` "filters" a sequence of objects with a boolean function -- -It keeps only those for which the function is True - -To get only the even numbers: - -.. code-block:: ipython - - In [27]: l = [2, 5, 7, 12, 6, 4] - In [28]: filter(lambda x: not x%2, l) - Out[28]: [2, 12, 6, 4] - - - -reduce ------- - -``reduce`` "reduces" a sequence of objects to a single object with a function that combines two arguments - -To get the sum: - -.. code-block:: ipython - - In [30]: l = [2, 5, 7, 12, 6, 4] - In [31]: reduce(lambda x,y: x+y, l) - Out[31]: 36 - - -To get the product: - -.. code-block:: ipython - - In [32]: reduce(lambda x,y: x*y, l) - Out[32]: 20160 - - -Comprehensions --------------- - -Couldn't you do all this with comprehensions? - -Yes: - -.. code-block:: ipython - - In [33]: [x+2 + 10 for x in l] - Out[33]: [14, 17, 19, 24, 18, 16] - In [34]: [x for x in l if not x%2] - Out[34]: [2, 12, 6, 4] - - -(Except Reduce) - -But Guido thinks almost all uses of reduce are really ``sum()`` - -Functional Programming ----------------------- - -Comprehensions and map, filter, reduce are all "functional programming" approaches} - -``map, filter`` and ``reduce`` pre-date comprehensions in Python's history - -Some people like that syntax better - -And "map-reduce" is a big concept these days for parallel processing of "Big Data" in NoSQL databases. - -(Hadoop, MongoDB, etc.) - - -A bit more about lambda ------------------------- - -Can also use keyword arguments} - -.. code-block:: ipython - - In [186]: l = [] - In [187]: for i in range(3): - l.append(lambda x, e=i: x**e) - .....: - In [189]: for f in l: - print f(3) - 1 - 3 - 9 - -Note when the keyword argument is evaluated: this turns out to be very handy! - -========= -Homework -========= - - -List comprehensions --------------------- - -Note: this is a bit of a "backwards" exercise -- -we show you code, you figure out what it does. - -As a result, not much to submit -- but so we can give you credit, submit -a file with a solution to the final problem. - -.. code-block:: python - - >>> feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals', 'fruit bats'] - - >>> comprehension = [delicacy.capitalize() for delicacy in feast] - -What is the output of: - -.. code-block:: python - - >>> comprehension[0] - ??? - - >>> comprehension[2] - ??? - -(figure it out before you try it) - -.. nextslide:: 2. Filtering lists with list comprehensions - - -.. code-block:: python - - >>> feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals', - 'fruit bats'] - - >>> comprehension = [delicacy for delicacy in feast if len(delicacy) > 6] - -What is the output of: - -.. code-block:: python - - >>> len(feast) - ??? - - >>> len(comprehension) - ??? - -(figure it out first!) - -.. nextslide:: 3. Unpacking tuples in list comprehensions - - -.. code-block:: python - - >>> list_of_tuples = [(1, 'lumberjack'), (2, 'inquisition'), (4, 'spam')] - - >>> comprehension = [ skit * number for number, skit in list_of_tuples ] - -What is the output of: - -.. code-block:: python - - >>> comprehension[0] - ??? - - >>> len(comprehension[2]) - ??? - -.. nextslide:: 4. Double list comprehensions - -.. code-block:: python - - >>> list_of_eggs = ['poached egg', 'fried egg'] - - >>> list_of_meats = ['lite spam', 'ham spam', 'fried spam'] - - >>> comprehension = [ '{0} and {1}'.format(egg, meat) for egg in list_of_eggs for meat in list_of_meats] - -What is the output of: - -.. code-block:: python - - >>> len(comprehension) - ??? - - >>> comprehension[0] - ??? - -.. nextslide:: 5. Set comprehensions - - -.. code-block:: python - - >>> comprehension = { x for x in 'aabbbcccc'} - -What is the output of: - -.. code-block:: python - - >>> comprehension - ??? - -.. nextslide:: 6. Dictionary comprehensions - - -.. code-block:: python - - >>> dict_of_weapons = {'first': 'fear', - 'second': 'surprise', - 'third':'ruthless efficiency', - 'forth':'fanatical devotion', - 'fifth': None} - >>> dict_comprehension = \ - { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} - -What is the output of: - -.. code-block:: python - - >>> 'first' in dict_comprehension - ??? - >>> 'FIRST' in dict_comprehension - ??? - >>> len(dict_of_weapons) - ??? - >>> len(dict_comprehension) - ??? - -.. nextslide:: Other resources - - -See also: - -https://github.com/gregmalcolm/python_koans - -https://github.com/gregmalcolm/python_koans/blob/master/python2/koans/about_comprehension.py - - -.. nextslide:: 7. Count even numbers - - -(submit this one to gitHub for credit on this assignment) - -This is from CodingBat "count_evens" (http://codingbat.com/prob/p189616) - -*Using a list comprehension*, return the number of even ints in the given array. - -Note: the % "mod" operator computes the remainder, e.g. ``5 % 2`` is 1. - -.. code-block:: python - - count_evens([2, 1, 2, 3, 4]) == 3 - - count_evens([2, 2, 0]) == 3 - - count_evens([1, 3, 5]) == 0 - - -.. code-block:: python - - def count_evens(nums): - one_line_comprehension_here - - -``dict`` and ``set`` comprehensions ------------------------------------- - -Let's revisiting the dict/set lab -- see how much you can do with -comprehensions instead. - -Specifically, look at these: - -First a slightly bigger, more interesting (or at least bigger..) dict: - -.. code-block:: python - - food_prefs = {"name": u"Chris", - u"city": u"Seattle", - u"cake": u"chocolate", - u"fruit": u"mango", - u"salad": u"greek", - u"pasta": u"lasagna"} - -.. nextslide:: Working with this dict: - -1. Print the dict by passing it to a string format method, so that you -get something like: - - "Chris is from Seattle, and he likes chocolate cake, mango fruit, - greek salad, and lasagna pasta" - -2. Using a list comprehension, build a dictionary of numbers from zero -to fifteen and the hexadecimal equivalent (string is fine). - -3. Do the previous entirely with a dict comprehension -- should be a one-liner - -4. Using the dictionary from item 1: Make a dictionary using the same -keys but with the number of 'a's in each value. You can do this either -by editing the dict in place, or making a new one. If you edit in place, -make a copy first! - -.. nextslide:: - -5. Create sets s2, s3 and s4 that contain numbers from zero through twenty, -divisible 2, 3 and 4. - - a. Do this with one set comprehension for each set. - - b. What if you had a lot more than 3? -- Don't Repeat Yourself (DRY) - - - create a sequence that holds all three sets - - - loop through that sequence to build the sets up -- so no repeated code. - - c. Extra credit: do it all as a one-liner by nesting a set comprehension inside a list comprehension. (OK, that may be getting carried away!) - - -lambda and keyword argument magic ------------------------------------ - -Write a function that returns a list of n functions, -such that each one, when called, will return the input value, -incremented by an increasing number. - -Use a for loop, ``lambda``, and a keyword argument - -( Extra credit ): - -Do it with a list comprehension, instead of a for loop - - -Not clear? here's what you should get - -.. nextslide:: Example calling code - -.. code-block:: ipython - - In [96]: the_list = function_builder(4) - ### so the_list should contain n functions (callables) - In [97]: the_list[0](2) - Out[97]: 2 - ## the zeroth element of the list is a function that add 0 - ## to the input, hence called with 2, returns 2 - In [98]: the_list[1](2) - Out[98]: 3 - ## the 1st element of the list is a function that adds 1 - ## to the input value, thus called with 2, returns 3 - In [100]: for f in the_list: - print f(5) - .....: - 5 - 6 - 7 - 8 - ### If you loop through them all, and call them, each one adds one more - to the input, 5... i.e. the nth function in the list adds n to the input. - - - - -Functional files ------------------ - -Write a program that takes a filename and "cleans" the file be removing all the leading and trailing whitespace from each line. - -Read in the original file and write out a new one, either creating a new file or overwriting the existing one. - -Give your user the option of which to perform. - -Use ``map()`` to do the work. - -Write a second version using a comprehension. - -.. nextslide:: Hint - -``sys.argv`` hold the command line arguments the user typed in. If the user types: - -.. code-block:: bash - - $ python the_script a_file_name - -Then: - -.. code-block:: python - - import sys - filename = sys.argv[1] - -will get ``filename == "a_file_name"`` - - -Recommended Reading ---------------------- - -* LPTHW: Ex 40 - 45 - -http://learnpythonthehardway.org/book/ - -* Dive Into Python: chapter 4, 5 - -http://www.diveintopython.net/toc/index.html - diff --git a/slides_sources/source/session07.rst b/slides_sources/source/session07.rst deleted file mode 100644 index 68a4b19f..00000000 --- a/slides_sources/source/session07.rst +++ /dev/null @@ -1,976 +0,0 @@ - -.. Foundations 2: Python slides file, created by - hieroglyph-quickstart on Wed Apr 2 18:42:06 2014. - -******************************* -Session Seven: Testing, More OO -******************************* - -.. rst-class:: large centered - -| Testing, -| Multiple Inheritance, -| Properties, -| Class and Static Methods, -| Special (Magic) Methods - - -Review/Questions -================ - -Review of Previous Class ------------------------- - -* Unicode - -* Object Oriented Programming - - -Homework review ---------------- - -Homework Questions? - -How is progress going on the HTML Renderer? - - -Testing -======= - -.. rst-class:: build left -.. container:: - - You've already seen some a very basic testing strategy. - - You've written some tests using that strategy. - - These tests were pretty basic, and a bit awkward in places (testing error - conditions in particular). - - .. rst-class:: centered - - **It gets better** - -Test Runners ------------- - -So far our tests have been limited to code in an ``if __name__ == "__main__":`` -block. - -.. rst-class:: build - -* They are run only when the file is executed -* They are always run when the file is executed -* You can't do anything else when the file is executed without running tests. - -.. rst-class:: build -.. container:: - - This is not optimal. - - Python provides testing systems to help. - - -.. nextslide:: Standard Library: ``unittest`` - -The original testing system in Python. - -You write subclasses of the ``unittest.TestCase`` class: - -.. code-block:: python - - # in test.py - import unittest - - class MyTests(unittest.TestCase): - def test_tautology(self): - self.assertEquals(1, 1) - -Then you run the tests by using the ``main`` function from the ``unittest`` -module: - -.. code-block:: python - - # in test.py - if __name__ == '__main__': - unittest.main() - -.. nextslide:: Testing Your Code - -This way, you can write your code in one file and test it from another: - -.. code-block:: python - - # in my_mod.py - def my_func(val1, val2): - return val1 * val2 - - # in test_my_mod.py - import unittest - from my_mod import my_func - - class MyFuncTestCase(unittest.TestCase): - def test_my_func(self): - test_vals = (2, 3) - expected = reduce(lambda x, y: x * y, test_vals) - actual = my_func(*test_vals) - self.assertEquals(expected, actual) - - if __name__ == '__main__': - unittest.main() - -.. nextslide:: Advantages of ``unittest`` - -.. rst-class:: build -.. container:: - - The ``unittest`` module is great. - - It comes with the standard Python distribution, no installation required. - - It provides a wide variety of assertions for testing all sorts of situations. - - It allows for a setup and tear down workflow both before and after all tests - and before and after each test. - - It's well known and well understood. - -.. nextslide:: Disadvantages: - -.. rst-class:: build -.. container:: - - - It's Object Oriented, and quite heavy. - - It uses the framework design pattern, so knowing how to use the features - means learning what to override. - - Needing to override means you have to be cautious. - - Test discovery is both inflexible and brittle. - -.. nextslide:: Other Options - -There are several other options for running tests in Python. - - -* `Nose`_ -* `pytest`_ -* ... (many frameworks supply their own test runners) - -We are going to play today with pytest - -.. _Nose: https://nose.readthedocs.org/ -.. _pytest: http://pytest.org/latest/ - - -.. nextslide:: Installing ``pytest`` - -The first step is to install the package: - -.. code-block:: bash - - $ workon cff2py - (cff2py)$ pip install pytest - -Once this is complete, you should have a ``py.test`` command you can run at the -command line: - -.. code-block:: bash - - (cff2py)$ py.test - -If you have any tests in your repository, that will find and run them. - -.. rst-class:: build -.. container:: - - **Do you?** - -.. nextslide:: Pre-existing Tests - -I've added two files to the ``code/session07`` folder, along with a python -source code file called ``circle.py``. - -The results you should have seen when you ran ``py.test`` above come partly -from these files. - -Let's take a few minutes to look these files over. - -[demo] - -.. nextslide:: What's Happening Here. - -When you run the ``py.test`` command, ``pytest`` starts in your current working -directory and searches the filesystem for things that might be tests. - -It follows some simple rules: - -.. rst-class:: build - -* Any python file that starts with ``test_`` or ``_test`` is imported. -* Any functions in them that start with ``test_`` are run as tests. -* Any classes that start with ``Test`` are treated similarly, with methods that - begin with ``test_`` treated as tests. - - -.. nextslide:: - -This test running framework is simple, flexible and configurable. - -`Read the documentation`_ for more information. - -.. _Read the documentation: http://pytest.org/latest/getting-started.html#getstarted - -.. nextslide:: Test Driven Development - -What we've just done here is the first step in what is called **Test Driven -Development**. - -A bunch of tests exist, but the code to make them pass does not yet exist. - -The red we see in the terminal when we run our tests is a goad to us to write -the code that fixes these tests. - -Let's do that next! - - -More on Subclassing -=================== - -Watch This Video: - -http://pyvideo.org/video/879/the-art-of-subclassing - -.. rst-class:: left - -Seriously, well worth the time. - -What's a Subclass For? ----------------------- - -The most salient points from that video are as follows: - -**Subclassing is not for Specialization** - -**Subclassing is for Reusing Code** - -**Bear in mind that the subclass is in charge** - - -Multiple Inheritance --------------------- - -Multiple inheritance: Inheriting from more than one class - -Simply provide more than one parent. - -.. code-block:: python - - class Combined(Super1, Super2, Super3): - def __init__(self, something, something else): - # some custom initialization here. - Super1.__init__(self, ......) - Super2.__init__(self, ......) - Super3.__init__(self, ......) - # possibly more custom initialization - - -(calls to the super class ``__init__`` are optional -- case dependent) - -.. nextslide:: Method Resolution Order - -.. code-block:: python - - class Combined(Super1, Super2, Super3) - -Attributes are located bottom-to-top, left-to-right - -* Is it an instance attribute ? -* Is it a class attribute ? -* Is it a superclass attribute ? - - * is the it an attribute of the left-most superclass? - * is the it an attribute of the next superclass? - * and so on up the hierarchy... - -* Is it a super-superclass attribute ? -* ... also left to right ... - -http://python-history.blogspot.com/2010/06/method-resolution-order.html - -.. nextslide:: Mix-ins - -Provides an subset of expected functionality in a re-usable package. - -Why would you want to do this? - -Hierarchies are not always simple: - -* Animal - - * Mammal - - * GiveBirth() - - * Bird - - * LayEggs() - -Where do you put a Platypus? - -Real World Example: `FloatCanvas`_ - -.. _FloatCanvas: https://github.com/svn2github/wxPython/blob/master/3rdParty/FloatCanvas/floatcanvas/FloatCanvas.py#L485 - -**Careful About This Pattern** - - -.. nextslide:: New-Style Classes - -All the class definitions we've been showing inherit from ``object``. - -This is referred to as a "new style" class. - -They were introduced in python2.2 to better merge types and classes, and clean -up a few things. - -There are differences in method resolution order and properties. - -**Always Make New-Style Classes.** - -The differences are subtle, and may not appear until they jump up to bite you. - - -.. nextslide:: ``super()`` - -``super()``: use it to call a superclass method, rather than explicitly calling -the unbound method on the superclass. - -instead of: - -.. code-block:: python - - class A(B): - def __init__(self, *args, **kwargs) - B.__init__(self, *argw, **kwargs) - ... - -You can do: - -.. code-block:: python - - class A(B): - def __init__(self, *args, **kwargs) - super(A, self).__init__(*argw, **kwargs) - ... - -.. nextslide:: Caveats - -Caution: There are some subtle differences with multiple inheritance. - -You can use explicit calling to ensure that the 'right' method is called. - - -.. nextslide:: Background - -Two seminal articles about ``super()``: - -"Super Considered Harmful" -- James Knight - -https://fuhm.net/super-harmful/ - -"super() considered super!" -- Raymond Hettinger - -http://rhettinger.wordpress.com/2011/05/26/super-considered-super/} - -(Both worth reading....) - - -Properties -========== - -.. rst-class:: left -.. container:: - - One of the strengths of Python is lack of clutter. - - Attributes are simple and concise: - - .. code-block:: ipython - - In [5]: class C(object): - def __init__(self): - self.x = 5 - In [6]: c = C() - In [7]: c.x - Out[7]: 5 - In [8]: c.x = 8 - In [9]: c.x - Out[9]: 8 - - -Getter and Setters? -------------------- - -But what if you need to add behavior later? - -.. rst-class:: build - -* do some calculation -* check data validity -* keep things in sync - - -.. nextslide:: - -.. code-block:: ipython - - In [5]: class C(object): - ...: def __init__(self): - ...: self.x = 5 - ...: def get_x(self): - ...: return self.x - ...: def set_x(self, x): - ...: self.x = x - ...: - In [6]: c = C() - In [7]: c.get_x() - Out[7]: 5 - In [8]: c.set_x(8) - In [9]: c.get_x() - Out[9]: 8 - - - This is ugly and verbose -- `Java`_? - -.. _Java: http://dirtsimple.org/2004/12/python-is-not-java.html - -.. nextslide:: properties - -When (and if) you need them: - -.. code-block:: python - - class C(object): - def __init__(self, x=5): - self._x = x - def _getx(self): - return self._x - def _setx(self, value): - self._x = value - def _delx(self): - del self._x - x = property(_getx, _setx, _delx, doc="docstring") - -Now the interface is still like simple attribute access! - -.. rst-class:: centered small - -[demo: :download:`properties_example.py <./supplements/properties_example.py>`] - - -.. nextslide:: "Read Only" Attributes - -Not all the arguments to ``property`` are required. - -You can use this to create attributes that are "read only": - -.. code-block:: ipython - - In [11]: class D(object): - ....: def __init__(self, x=5): - ....: self._x = 5 - ....: def getx(self): - ....: return self._x - ....: x = property(getx, doc="I am read only") - ....: - In [12]: d = D() - In [13]: d.x - Out[13]: 5 - In [14]: d.x = 6 - --------------------------------------------------------------------------- - AttributeError Traceback (most recent call last) - in () - ----> 1 d.x = 6 - AttributeError: can't set attribute - - -.. nextslide:: Syntactic Sugar - -This *imperative* style of adding a ``property`` to you class is clear, but -it's still a little verbose. - -It also has the effect of leaving all those defined method objects laying -around: - -.. code-block:: ipython - - In [19]: d.x - Out[19]: 5 - In [20]: d.getx - Out[20]: > - In [21]: d.getx() - Out[21]: 5 - -.. nextslide:: - -Python provides us with a way to solve both these issues at once, using a -syntactic feature called **decorators** (more about these next session): - -.. code-block:: ipython - - In [22]: class E(object): - ....: def __init__(self, x=5): - ....: self._x = x - ....: @property - ....: def x(self): - ....: return self._x - ....: @x.setter - ....: def x(self, value): - ....: self._x = value - ....: - In [23]: e = E() - In [24]: e.x - Out[24]: 5 - In [25]: e.x = 6 - In [26]: e.x - Out[26]: 6 - - -Static and Class Methods -======================== - -.. rst-class:: left build -.. container:: - - You've seen how methods of a class are *bound* to an instance when it is - created. - - And you've seen how the argument ``self`` is then automatically passed to - the method when it is called. - - And you've seen how you can call *unbound* methods on a class object so - long as you pass an instance of that class as the first argument. - - .. rst-class:: centered - - **But what if you don't want or need an instance?** - - -Static Methods --------------- - -A *static method* is a method that doesn't get self: - -.. code-block:: ipython - - In [36]: class StaticAdder(object): - ....: def add(a, b): - ....: return a + b - ....: add = staticmethod(add) - ....: - - In [37]: StaticAdder.add(3, 6) - Out[37]: 9 - -.. rst-class:: centered - -[demo: :download:`static_method.py <./supplements/static_method.py>`] - - -.. nextslide:: Syntactic Sugar - -Like ``properties``, static methods can be written *declaratively* using the -``staticmethod`` built-in as a *decorator*: - -.. code-block:: python - - class StaticAdder(object): - @staticmethod - def add(a, b): - return a + b - -.. nextslide:: Why? - -.. rst-class:: build -.. container:: - - Where are static methods useful? - - Usually they aren't - - 99% of the time, it's better just to write a module-level function - - An example from the Standard Library (tarfile.py): - - .. code-block:: python - - class TarInfo(object): - # ... - @staticmethod - def _create_payload(payload): - """Return the string payload filled with zero bytes - up to the next 512 byte border. - """ - blocks, remainder = divmod(len(payload), BLOCKSIZE) - if remainder > 0: - payload += (BLOCKSIZE - remainder) * NUL - return payload - - -Class Methods -------------- - -A class method gets the class object, rather than an instance, as the first -argument - -.. code-block:: ipython - - In [41]: class Classy(object): - ....: x = 2 - ....: def a_class_method(cls, y): - ....: print "in a class method: ", cls - ....: return y ** cls.x - ....: a_class_method = classmethod(a_class_method) - ....: - In [42]: Classy.a_class_method(4) - in a class method: - Out[42]: 16 - -.. rst-class:: centered - -[demo: :download:`class_method.py <./supplements/class_method.py>`] - -.. nextslide:: Syntactic Sugar - -Once again, the ``classmethod`` built-in can be used as a *decorator* for a -more declarative style of programming: - -.. code-block:: python - - class Classy(object): - x = 2 - @classmethod - def a_class_method(cls, y): - print "in a class method: ", cls - return y ** cls.x - -.. nextslide:: Why? - -.. rst-class:: build -.. container:: - - Unlike static methods, class methods are quite common. - - They have the advantage of being friendly to subclassing. - - Consider this: - - .. code-block:: ipython - - In [44]: class SubClassy(Classy): - ....: x = 3 - ....: - - In [45]: SubClassy.a_class_method(4) - in a class method: - Out[45]: 64 - -.. nextslide:: Alternate Constructors - -Because of this friendliness to subclassing, class methods are often used to -build alternate constructors. - -Consider the case of wanting to build a dictionary with a given iterable of -keys: - -.. code-block:: ipython - - In [57]: d = dict([1,2,3]) - --------------------------------------------------------------------------- - TypeError Traceback (most recent call last) - in () - ----> 1 d = dict([1,2,3]) - - TypeError: cannot convert dictionary update sequence element #0 to a sequence - - -.. nextslide:: ``dict.fromkeys()`` - -The stock constructor for a dictionary won't work this way. So the dict object -implements an alternate constructor that *can*. - -.. code-block:: python - - @classmethod - def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S. - If not specified, the value defaults to None. - - ''' - self = cls() - for key in iterable: - self[key] = value - return self - -(this is actually from the OrderedDict implementation in ``collections.py``) - -See also datetime.datetime.now(), etc.... - -.. nextslide:: Curious? - -Properties, Static Methods and Class Methods are powerful features of Pythons -OO model. - -They are implemented using an underlying structure called *descriptors* - -`Here is a low level look`_ at how the descriptor protocol works. - -The cool part is that this mechanism is available to you, the programmer, as -well. - -.. _Here is a low level look: https://docs.python.org/2/howto/descriptor.html - - -Kicking the Tires ------------------ - -Copy the file ``code/session07/circly.py`` to your student folder. - -In it, write a simple "Circle" class: - -.. code-block:: ipython - - In [13]: c = Circle(3) - In [15]: c.diameter - Out[15]: 6.0 - In [16]: c.diameter = 8 - In [17]: c.radius - Out[17]: 4.0 - In [18]: c.area - Out[18]: 50.26548245743669 - - -Use ``properties`` so you can keep the radius and diameter in sync, and the -area computed on the fly. - -Extra Credit: use a class method to make an alternate constructor that takes -the diameter instead. - - -.. nextslide:: - -Also copy the file ``test_circle1.py`` to your student folder. - -As you work, run the tests: - -.. code-block:: bash - - (cff2py)$ py.test test_circle1.py - -As each of the requirements from above are fulfilled, you'll see tests 'turn -green'. - -When all your tests are passing, you've completed the job. - -(This clear finish line is another of the advantages of TDD) - - -Special Methods -=============== - -.. rst-class:: left -.. container:: - - Special methods (also called *magic* methods) are the secret sauce to Python's - Duck typing. - - Defining the appropriate special methods in your classes is how you make your - class act like standard classes. - -What's in a Name? ------------------ - -We've seen at least one special method so far:: - - __init__ - -It's all in the double underscores... - -Pronounced "dunder" (or "under-under") - -try: ``dir(2)`` or ``dir(list)`` - -.. nextslide:: Protocols - -.. rst-class:: build -.. container:: - - The set of special methods needed to emulate a particular type of Python object - is called a *protocol*. - - Your classes can "become" like Python built-in classes by implementing the - methods in a given protocol. - - Remember, these are more *guidelines* than laws. Implement what you need. - - -.. nextslide:: The Numerics Protocol - -Do you want your class to behave like a number? Implement these methods: - -.. code-block:: python - - object.__add__(self, other) - object.__sub__(self, other) - object.__mul__(self, other) - object.__floordiv__(self, other) - object.__mod__(self, other) - object.__divmod__(self, other) - object.__pow__(self, other[, modulo]) - object.__lshift__(self, other) - object.__rshift__(self, other) - object.__and__(self, other) - object.__xor__(self, other) - object.__or__(self, other) - -.. nextslide:: The Container Protocol - -Want to make a container type? Here's what you need: - -.. code-block:: python - - object.__len__(self) - object.__getitem__(self, key) - object.__setitem__(self, key, value) - object.__delitem__(self, key) - object.__iter__(self) - object.__reversed__(self) - object.__contains__(self, item) - object.__getslice__(self, i, j) - object.__setslice__(self, i, j, sequence) - object.__delslice__(self, i, j) - - -.. nextslide:: An Example - -Each of these methods supports a common Python operation. - -For example, to make '+' work with a sequence type in a vector-like fashion, implement ``__add__``: - -.. code-block:: python - - def __add__(self, v): - """return the element-wise vector sum of self and v - """ - assert len(self) == len(v) - return vector([x1 + x2 for x1, x2 in zip(self, v)]) - -.. rst-class:: centered - -[a more complete example may be seen :download:`here <./supplements/vector.py>`] - - -.. nextslide:: Generally Useful Special Methods - -You only *need* to define the special methods that will be used by your class. - -However, even in the absence of wanting to duck-type, you should almost always -define these: - -``object.__str__``: - Called by the str() built-in function and by the print statement to compute - the *informal* string representation of an object. - -``object.__unicode__``: - Called by the unicode() built-in function. This converts an object to an - *informal* unicode representation. - -``object.__repr__``: - Called by the repr() built-in function and by string conversions (reverse - quotes) to compute the *official* string representation of an object. - - (ideally: ``eval( repr(something) ) == something``) - -.. nextslide:: Summary - -Use special methods when you want your class to act like a "standard" class in -some way. - -Look up the special methods you need and define them. - -There's more to read about the details of implementing these methods: - -* https://docs.python.org/2/reference/datamodel.html#special-method-names -* http://www.rafekettler.com/magicmethods.html - -Be a bit cautious about the code examples in that last one. It uses quite a bit -of old-style class definitions, which should not be emulated. - - -Kicking the Tires ------------------ - -Extend your "Circle" class: - -* Add ``__str__`` and ``__repr__`` methods -* Write an ``__add__`` method so you can add two circles -* Make it so you can multiply a circle by a number.... - -.. code-block:: ipython - - In [22]: c1 = Circle(3) - In [23]: c2 = Circle(4) - In [24]: c3 = c1+c2 - In [25]: c3.radius - Out[25]: 7 - In [26]: c1*3 - Out[26]: Circle(9) - -If you have time: compare them... (``c1 > c2`` , etc) - - -.. nextslide:: - -As you work, run the tests in ``test_circle2.py``: - -.. code-block:: bash - - (cff2py)$ py.test test_circle2.py - -As each of the requirements from above are fulfilled, you'll see tests 'turn -green'. - -When all your tests are passing, you've completed the job. - - -Homework -======== - -.. rst-class:: centered large - -Testing, Testing, 1 2 3 - - -Assignment ----------- - -If you are not yet done, complete the ``Circle`` class so that all tests in -``test_circle2.py`` pass. - -Go back over some of your assignments from the last weeks. - -Convert tests that are currently in the ``if __name__ == '__main__':`` blocks -into standalone pytest files. - -Name each test file so that it is clear with which source file it belongs:: - - test_rot13.py -> rot13.py - -Add unit tests for the HTML Renderer that you are currently constructing. - -Create at least 4 test files with tests that well exercise the features built -in each source file. - diff --git a/slides_sources/source/supplements/class_method.py b/slides_sources/source/supplements/class_method.py deleted file mode 100644 index e8544c08..00000000 --- a/slides_sources/source/supplements/class_method.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -""" -example of a class method -""" - - -class C(object): - def __init__(self, x, y): - self.x = x - self.y = y - - def a_class_method(klass, y): - print "in a_class_method", klass - return klass(y, y**2) - a_class_method = classmethod(a_class_method) - - -class C2(C): - pass - - -if __name__ == "__main__": - - c = C(3, 4) - print type(c), c.x, c.y - - c2 = C.a_class_method(3) - print type(c2), c2.x, c2.y - - c3 = c2.a_class_method(2) - print type(c3), c3.x, c3.y diff --git a/slides_sources/source/supplements/index.rst b/slides_sources/source/supplements/index.rst deleted file mode 100644 index aef9e219..00000000 --- a/slides_sources/source/supplements/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -Supplemental Materials -====================== - -.. toctree:: - :maxdepth: 1 - - python_learning_resources - python_for_mac - python_for_windows - python_for_linux - virtualenv - sublime_as_ide - shell - unicode diff --git a/slides_sources/source/supplements/properties_example.py b/slides_sources/source/supplements/properties_example.py deleted file mode 100644 index ab5e6745..00000000 --- a/slides_sources/source/supplements/properties_example.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -""" -example code for properties - -NOTE: if your getters and setters are this simple: don't do this! - -""" - -class C(object): - _x = None - def getx(self): - return self._x - def setx(self, value): - self._x = value - def delx(self): - del self._x - x = property(getx, setx, delx, "docstring") - -if __name__ == "__main__": - c = C - c.x = 5 - print c.x - diff --git a/slides_sources/source/supplements/python_for_linux.rst b/slides_sources/source/supplements/python_for_linux.rst deleted file mode 100644 index 183be0f5..00000000 --- a/slides_sources/source/supplements/python_for_linux.rst +++ /dev/null @@ -1,96 +0,0 @@ -*********************************************************** -Setting up Linux for Python and this class -*********************************************************** - -NOTE: this is from memory: no system to test on right now. - -================== -Getting The Tools -================== - -Python -------- - -You probably already have python. Try: - -.. code-block:: bash - - $ python - Python 2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35) - [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on linux - -You can see what version you've got. If you don't have 2.7.*, then you'll need to go try to find a newer version -- your distribution may have a package named something like: - -.. code-block:: bash - - $ apt-get install python2.7 - -Or ``yum install`` or ??? - - -Terminal ---------- - -Every Linux box has a terminal emulator -- find and use it. - - - -git ----- - -git is likely to be there on your system already, but if not: - -.. code-block:: bash - - $apt-get install git - -pip ---- - -``pip`` is the Python package installer. - -Many python packages are also available directly from your distro -- but you'll get the latest and greatest if you use ``pip`` to install it instead. - -To get pip, the first option is to use your system package manager, something like: - -.. code-block:: bash - - $apt-get install python-pip - -If that doesn't work, you can get it from: - -https://pip.pypa.io/en/latest/installing.html - -download ``get-pip.py`` from that site, and run it with python:: - - $ python get-pip.py - -It should download and install ``pip`` (and ``setuptools``) - -You can now use pip to install other packages. - -iPython --------- - -One we are going to use in class is ``iPython``:: - - $ pip install ipython - -You should now be able to run ``iPython``:: - - $ ipython - Python 2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35) - Type "copyright", "credits" or "license" for more information. - - IPython 2.0.0 -- An enhanced Interactive Python. - ? -> Introduction and overview of IPython's features. - %quickref -> Quick reference. - help -> Python's own help system. - object? -> Details about 'object', use 'object??' for extra details. - - - - - - - diff --git a/slides_sources/source/supplements/python_for_mac.rst b/slides_sources/source/supplements/python_for_mac.rst deleted file mode 100644 index a3d5541e..00000000 --- a/slides_sources/source/supplements/python_for_mac.rst +++ /dev/null @@ -1,108 +0,0 @@ -*********************************************************** -Setting up your Mac for Python and this class -*********************************************************** - -================== -Getting The Tools -================== - -OS-X comes with Python out of the box, but not the full setup you'll need for development, and this class. - -**Note**: - -If you use ``macports`` or ``homebrew`` to manage \*nix software on your machine, feel free to use those for ``python``, ``git``, etc, as well. If not, then read on. - -Python -------- - -While OS-X does provide python our of the box -- it tends not to have the latest version, and you really don't want to mess with the system installation. So I recommend installing an independent installation from ``python.org``: - -Download and install Python 2.7.8 from Python.org: - -https://www.python.org/ftp/python/2.7.8/python-2.7.8-macosx10.6.dmg - -Simple as that. - -Terminal ---------- - -The built-in "terminal" application works fine. Find it in: - -:: - - /Applications/Utilities/Terminal - -Drag it to the dock to easy access. - -git ----- - -Get a git client -- the gitHub GUI client may be nice -- I honestly don't know. - -There are a couple options for a command line client. - -This one: - -http://sourceforge.net/projects/git-osx-installer/ - -Is a big download and install, but has everything you need out of the box. - -This one: - -http://git-scm.com/download/mac - -Works great, but you need the XCode command line tools to run it. If you already have that, or expect to need a compiler anyway, then this is a good option. - -You can get XCode from the Apple App Store. - -(If you try running "git" on the command line after installing, it should send you there). - -Warning: XCode is a BIG download. Once installed, run it so it can initialize itself. - -After either of these is installed, the ``git`` command should work: - -.. code-block:: bash - - $ git --version - git version 1.8.5.2 (Apple Git-48) - -pip ---- - -``pip`` is the Python package installer. Unfortunately, it doesn't come out of the box with Python2.7, so you need to install it: - -https://pip.pypa.io/en/latest/installing.html - -download ``get-pip.py`` from that site, and run it with python:: - - $ python get-pip.py - -It should download and install ``pip`` (and ``setuptools``) - -You can now use pip to install other packages. - -iPython --------- - -One we are going to use in class is ``iPython``:: - - $ pip install ipython - -You should now be able to run ``iPython``:: - - $ ipython - Python 2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35) - Type "copyright", "credits" or "license" for more information. - - IPython 2.0.0 -- An enhanced Interactive Python. - ? -> Introduction and overview of IPython's features. - %quickref -> Quick reference. - help -> Python's own help system. - object? -> Details about 'object', use 'object??' for extra details. - - - - - - - diff --git a/slides_sources/source/supplements/python_for_windows.rst b/slides_sources/source/supplements/python_for_windows.rst deleted file mode 100644 index fccdfbed..00000000 --- a/slides_sources/source/supplements/python_for_windows.rst +++ /dev/null @@ -1,104 +0,0 @@ -*********************************************************** -Setting up Windows for Python and this class -*********************************************************** - -NOTE: this is from memory: no system to test on right now. - -================== -Getting The Tools -================== - -Python -------- - -There are a number of python distributions available -- many designed for easier support of scientific programming: - -Anaconda -Enthought Canopy -Python(x,y) - -But for core use, the installer from python.org is the way to go: - -https://www.python.org/downloads/ - -You want the installer for Python 2.7.8 -- probably 64 bit, though if you have a 32 bit sytem, you can get that. There is essentially no difference for the purposes of this course. - -Double click and install. - - -Terminal ---------- - -You can use the "DOS Box" as a terminal, though the newer "powershell" is a better option. - -But to use the Python in the terminal efectively, you need to put a couple paths on your "PATH" environment variable: - -http://www.computerhope.com/issues/ch000549.htm - -You want to add: - -``C:\Python2.7`` - -and - -``C:\Python2.7\Scripts`` - -to ``PATH`` - - -git ----- - -Get a git client -- the gitHub GUI client may be nice -- I honestly don't know. - -There is also ToroiseGit: - -https://code.google.com/p/tortoisegit/ - -which integrates git with the filemanager. But for the purposes of learning, it may be better to use a command line client: - -http://git-scm.com/download/win - -I think that gives you a "Git bash shell" -- a command window that gives you a \*nix - like command line shell. - - -pip ---- - -``pip`` is the Python package installer. Unfortunately, it doesn't come out of the box with Python2.7, so you need to install it: - -https://pip.pypa.io/en/latest/installing.html - -download ``get-pip.py`` from that site, and run it with python:: - - $ python get-pip.py - -It should download and install ``pip`` (and ``setuptools``) - -You can now use pip to install other packages. - -iPython --------- - -One we are going to use in class is ``iPython``:: - - $ pip install ipython - -You should now be able to run ``iPython``:: - - $ ipython - Python 2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35) - Type "copyright", "credits" or "license" for more information. - - IPython 2.0.0 -- An enhanced Interactive Python. - ? -> Introduction and overview of IPython's features. - %quickref -> Quick reference. - help -> Python's own help system. - object? -> Details about 'object', use 'object??' for extra details. - - - - - - - diff --git a/slides_sources/source/supplements/static_method.py b/slides_sources/source/supplements/static_method.py deleted file mode 100644 index 2fe04e7c..00000000 --- a/slides_sources/source/supplements/static_method.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -""" -examples of static and class methods -""" - -class C(object): - - def a_static_method(a, b): - print "in a_static_method" - return a+b - a_static_method = staticmethod(a_static_method) - - def test(self): - return self.a_static_method(2,3) - -if __name__ == "__main__": - - print C.a_static_method(3,4) - - c = C() - - print c.a_static_method(4,5) diff --git a/slides_sources/source/supplements/vector.py b/slides_sources/source/supplements/vector.py deleted file mode 100644 index 56ee2404..00000000 --- a/slides_sources/source/supplements/vector.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Vector type with +, * redefined as vector addition and dot product -From Jon Jacky's Intro to Python course: - http://staff.washington.edu/jon/python-course/ -""" - - -class vector(list): - def __repr__(self): - """ - String representation, uses list (superclass) representation - """ - return 'vector(%s)' % super(vector, self).__repr__() - - def __add__(self, v): - """ - redefine + as element-wise vector sum - """ - assert len(self) == len(v) - return vector([x1 + x2 for x1, x2 in zip(self, v)]) - - def __mul__(self, v): - """ - redefine * as vector dot product - """ - assert len(self) == len(v) - return sum([x1 * x2 for x1, x2 in zip(self, v)]) - -l1 = [1, 2, 3] -l2 = [4, 5, 6] -v1 = vector(l1) -v2 = vector(l2) - -if __name__ == '__main__': - print 'l1' - print l1 - print 'l1 + l2' - print l1 + l2 - # print l1 * l2 # TypeError - print 'zip(l1, l2)' - print zip(l1, l2) - print 'v1' - print v1 - print 'v1 + v2' - print v1 + v2 - print 'v1 * v2' - print v1 * v2 diff --git a/supplements/git_overview.html b/supplements/git_overview.html new file mode 100644 index 00000000..1e7f9b14 --- /dev/null +++ b/supplements/git_overview.html @@ -0,0 +1,364 @@ + + + + + + + + + + + git Overview — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        git Overview

        +
        +

        Resources

        +

        Pro git

        +

        The semi-offical documentation – the first few chapters are worth going through:

        +

        https://git-scm.com/book/en

        +

        Reading suggested at the end of session 1:

        +

        http://rogerdudler.github.io/git-guide/

        +

        https://try.github.io/levels/1/challenges/1

        +

        ** git Branching: getting fancy **

        +

        Interactive tutorial about branching – try it right in the browser!

        +

        http://pcottle.github.io/learnGitBranching/

        +
        +
        +

        A Graphical Tutorial

        +
        +

        A Picture of git

        +
        +../_images/git_simple_timeline.png +
        +
        +

        A git repository is a set of points in time, with history showing where +you’ve been.

        +

        Each point has a name (here A, B, C) that uniquely identifies it, +called a hash

        +

        The path from one point to the previous is represented by the difference +between the two points.

        +
        +
        +../_images/git_head.png +
        +
        +

        Each point in time can also have a label that points to it.

        +

        One of these is HEAD, which always points to the place in the timeline +that you are currently looking at.

        +
        +
        +../_images/git_master_branch.png +
        +
        +

        You may also be familiar with the label “master”.

        +

        This is the name that git automatically gives to the first branch in a +repository.

        +

        A branch is actually just a label that points to a specific point in +time.

        +
        +
        +../_images/git_new_commit.png +
        +
        +

        When you make a commit in git, you add a new point to the timeline.

        +

        The HEAD label moves to this new point.

        +

        So does the label for the branch you are on.

        +
        +
        +../_images/git_new_branch.png +
        +
        +

        You can make a new branch with the branch command.

        +

        This adds a new label to the current commit.

        +

        Notice that it does not check out that branch.

        +
        +
        +../_images/git_checkout_branch.png +
        +
        +

        You can use the checkout command to switch to the new branch.

        +

        This associates the HEAD label with the session01 label.

        +

        Use git branch to see which branch is active:

        +
        $ git branch
        +  master
        +* session01
        +
        +
        +
        +
        +../_images/git_commit_on_branch.png +
        +
        +

        While it is checked out, new commits move the session01 label.

        +

        Notice that HEAD is always the same as “where you are now”

        +
        +

        You can use this to switch between branches and make changes in isolation.

        +
        +
        +../_images/git_checkout_master.png +
        +
        +../_images/git_new_commit_on_master.png +
        +
        +
        +

        Branching allows you to keep related sets of work separate from each-other.

        +

        In class here, you can use it to do your exercises for each session.

        +

        Simply create a new branch for each session from your repository master +branch.

        +

        Do your work on that branch, and then you can issue a pull request in +github to have your work evaluated.

        +

        This is very much like how teams work in the “real world” so learning it +here will help you.

        +

        The final step in the process is merging your work.

        +
        +

        The merge command allows you to combine your work on one branch with the +work on another.

        +
        +

        It creates a new commit which reconciles the differences:

        +
        +../_images/git_merge_commit.png +
        +

        Notice that this commit has two parents.

        +
        +
        +

        Sometimes when you merge two branches, you get conflicts.

        +

        This happens when the same file was changed in about the same place in two +different ways.

        +

        Often, git can work these types of things out on its own, but if not, +you’ll need to manually edit files to fix the problem.

        +

        You’ll be helped by the fact that git will tell you which files are in +conflict.

        +

        Just open those files and look for conflict markers:

        +
        +
          +
        • <<<<<<<<< hash1 (stuff from the current branch)
        • +
        • ========= (the pivot point between two branches’ content)
        • +
        • >>>>>>>>> hash2 (stuff from the branch being merged)
        • +
        +
        +
        +

        Your job in fixing a conflict is to decide exactly what to keep.

        +

        You can (and should) communicate with others on your team when doing this.

        +

        Always remember to remove the conflict markers too. They are not syntactic +code in any language and will cause errors.

        +

        Once a conflict is resolved, you can git add the file back and then commit +the merge.

        +
        +
        +
        + + +
        +
        +
        + + + + +
        + +
        +

        + © Copyright 2014, Christopher Barker, Cris Ewing, . + +

        +
        + Built with Sphinx using a theme provided by Read the Docs. + +
        + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/index.html b/supplements/index.html new file mode 100644 index 00000000..25f94d44 --- /dev/null +++ b/supplements/index.html @@ -0,0 +1,229 @@ + + + + + + + + + + + Supplemental Materials — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/install_nano_win.html b/supplements/install_nano_win.html new file mode 100644 index 00000000..bd33927d --- /dev/null +++ b/supplements/install_nano_win.html @@ -0,0 +1,235 @@ + + + + + + + + + + + Installing Nano on Windows — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/packaging.html b/supplements/packaging.html new file mode 100644 index 00000000..5172925c --- /dev/null +++ b/supplements/packaging.html @@ -0,0 +1,643 @@ + + + + + + + + + + + Packages and Packaging — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Packages and Packaging

        +
        +

        Modules and Packages

        +

        A module is a file (something.py) with python code in it

        +

        A package is a directory with an __init__.py file in it

        +

        And usually other modules, packages, etc...

        +
        my_package
        +    __init__.py
        +    module_a.py
        +    module_b.py
        +
        +
        +
        import my_package
        +
        +
        +

        runs the code my_package/__init__.py (if there is any)

        +
        +
        +

        Modules and Packages

        +
        import sys
        +for p in sys.path:
        +    print p
        +
        +
        +

        (demo)

        +
        +
        +

        Installing Python

        +

        Linux:

        +

        Usually part of the system – just use it.

        +

        Windows:

        +

        Use the python.org version:

        +
          +
        • System Wide
        • +
        • Can install multiple versions if need be
        • +
        • Third party binaries for it.
        • +
        +
        +
        +

        Installing Python

        +

        OS-X:

        +

        Comes with the system, but:

        +
        +
          +
        • Apple has never upgraded within a release
        • +
        • There are non-open source components
        • +
        • Third party packages may or may not support it
        • +
        • Apple does use it – so don’t mess with it
        • +
        • I usually recommend the python.org version
        • +
        +
        +

        (Also Macports, Fink, Home Brew...)

        +
        +
        +

        Distributions

        +

        There are also a few “curated” distributions:

        +

        These provide python and a package management system for hard-to-buid packages.

        +

        Widely used by the scipy community +(lots of hard to build stuff that needs to work together...)

        +
        +
        +
        +
        +

        Installing Packages

        +

        Every Python installation has its own stdlib and site-packages folder

        +

        site-packages is the default place for third-party packages

        +
        +
        +

        Finding Packages

        +

        The Python Package Index:

        +

        PyPi

        +

        http://pypi.python.org/pypi

        +
        +
        +

        Installing Packages

        +

        From source

        +
          +
        • (setup.py install )
        • +
        • With the system installer (apt-get, yum, etc...)
        • +
        +

        From binaries:

        +
          +
        • Windows: MSI installers
        • +
        • OS-X: dmg installers (make sure to get compatible packages)
        • +
        • And now: binary wheels – (More and more of those available)
        • +
        • pip should find appropriate binary wheels if they are there.
        • +
        +

        In the beginning, there was the distutils:

        +

        But distutils is missing some key features:

        +
          +
        • package versioning
        • +
        • package discovery
        • +
        • auto-install
        • +
        +
          +
        • And then came PyPi
        • +
        • And then came setuptools
        • +
        • But that wasn’t well maintained...
        • +
        • Then there was distribute/pip
        • +
        • Which has now been merged back into setuptools
        • +
        +

        Now it’s pretty stable: pip+setuptools: use them.

        +
        +
        +

        Installing Packages

        +

        Actually, it’s still a bit of a mess

        +

        But getting better, and the mess is almost cleaned up.

        +
        +
        +

        Current State of Packaging

        +

        To build packages: distutils

        +
        +
        +

        For more features: setuptools

        +
        +
        +

        To install packages: pip

        +
        +
        +

        For binary packages: wheels

        +
        +
        +

        (installable by pip)

        +
        +
        +

        Compiled Packages

        +

        Biggest issue is with compiled extensions:

        +
        +
          +
        • (C/C++, Fortran, etc.)
        • +
        • You need the right compiler set up
        • +
        +
        +

        Dependencies:

        +
        +
          +
        • Here’s were it gets really ugly
        • +
        • Particularly on Windows
        • +
        +
        +

        Linux

        +

        Pretty straightforward:

        +
          +
        1. Is there a system package?
        2. +
        +
        +
          +
        • use it (apt-get install the_package)
        • +
        +
        +
          +
        1. Try pip install: it may just work!

          +
        2. +
        3. Install the dependencies, build from source:

          +
          python setup.py build
          +
          +python setup.py install
          +
          +
          +
        4. +
        +

        (may need “something-devel” packages)

        +

        Windows

        +

        Sometimes simpler:

        +
          +
        1. A lot of packages have Windows binaries:
        2. +
        +
        +
        +
        +
          +
        1. But if no binaries:
        2. +
        +
        +
          +
        • Hope the dependencies are available!
        • +
        • Set up the compiler
        • +
        +
        +

        MS now has a compiler just for python!

        +

        http://www.microsoft.com/en-us/download/details.aspx?id=44266

        +

        OS-X

        +
        +
        Lots of Python versions:
        +
          +
        • Apple’s built-in (different for each version of OS)
        • +
        • python.org builds
        • +
        • 32+64 bit Intel (and even PPC still kicking around)
        • +
        • Macports
        • +
        • Homebrew
        • +
        +
        +
        +

        Binary Installers (dmg or wheel) have to match python version

        +

        OS-X

        +

        If you have to build it yourself

        +

        Xcode compiler (the right version)

        +
        +
          +
        • Version 3.* for 32 bit PPC+Intel
        • +
        • Version > 4.* for 32+64 bit Intel
        • +
        +
        +

        (make sure to get the SDKs for older versions)

        +

        If extra dependencies:

        +
        +
          +
        • macports or homebrew often easiest way to build them
        • +
        +
        +
        +
        +

        Final Recommendations

        +

        First try: pip install

        +

        If that doesn’t work:

        +

        Read the docs of the package you want to install

        +

        Do what they say

        +

        (Or use Anaconda or Canopy)

        +
        +
        +

        virtualenv

        +

        virtualenv is a tool to create isolated Python environments.

        +

        Very useful for developing multiple apps

        +

        Or deploying more than one app on one system

        +

        http://www.virtualenv.org/en/latest/index.html}

        +

        Remember the notes from the beginning of class? virtualenv_section

        +

        (Cris will probably make you do this next class)

        +
        +
        +
        +

        Distributing

        +
        +

        Distributing

        +

        What if you need to distribute you own:

        +

        Scripts

        +

        Libraries

        +

        Applications

        +
        +
        +

        Scripts

        +

        Often you can just copy, share, or check in the script to source +control and call it good.

        +

        But only if it’s a single file, and doesn’t need anything non-standard

        +

        When the script needs more than just the stdlib

        +

        (or your company standard environment)

        +

        You have an application, not a script

        +
        +
        +

        Libraries

        +

        When you read the distutils docs, it’s usually libraries they’re talking about

        +

        Scripts + library is the same...

        +

        (http://docs.python.org/distutils/)

        +
        +
        +

        distutils

        +

        distutils makes it easy to do the easy stuff:

        +

        Distribute and install to multiple platforms, etc.

        +

        Even binaries, installers and compiled packages

        +

        (Except dependencies)

        +

        (http://docs.python.org/distutils/)

        +
        +
        +

        distutils basics

        +

        It’s all in the setup.py file:

        +

        (http://docs.python.org/distutils/)

        +
        +
        +

        distutils basics

        +

        Once your setup.py is written, you can:

        +
        python setup.py ...
        +build         build everything needed to install
        +install       install everything from build directory
        +sdist         create a source distribution
        +              (tarball, zip file, etc.)
        +bdist         create a built (binary) distribution
        +bdist_rpm     create an RPM distribution
        +bdist_wininst create an executable installer for MS Windows
        +upload        upload binary package to PyPI
        +
        +
        +
        +
        +

        wheels

        +

        “wheels” are the “new” package format for python.

        +

        A wheel is essentially a zip file of the entire package, ready to be +unpacked in the right place on installation.

        +

        pip will look for wheels for OS-X and Windows on PyPi, and auto-install +them if they exist

        +

        This is particularly nice for packages with non-python dependencies.

        +
        +
        +

        More complex packaging

        +

        For a complex package:

        +

        You want to use a well structured setup:

        +

        http://the-hitchhikers-guide-to-packaging.readthedocs.org/en/latest/

        +
        +
        +

        develop mode

        +

        While you are developing your package, Installing it is a pain.

        +

        But you want your code to be able to import, etc. as though it were installed

        +

        setup.py develop installs links to your code, rather than copies +– so it looks like it’s installed, but it’s using the original source

        +

        python setup.py develop

        +

        You need setuptools and a setup.py to use it.

        +
        +
        +

        Applications

        +

        For a complete application:

        +
        +
          +
        • Web apps
        • +
        • GUI apps
        • +
        +
        +

        Multiple options:

        +
        +
        +
        +
        +
        +

        Bundles

        +

        Bundles are Python + all your code + plus all the dependencies – +all in one single “bundle”

        +

        Most popular on Windows and OS-X

        +
        py2exe
        +py2app
        +pyinstaller
        +...
        +
        +
        +

        User doesn’t even have to know it’s python

        +

        Examples:

        +
        +
        +
        +
        +

        LAB

        +

        Write a setup.py for a script of yours

        +
        +
          +
        • Ideally, your script relies on at least one other module
        • +
        • At a minimum, you’ll need to specify scripts
        • +
        • and probably py_modules
        • +
        • try:
            +
          • python setup.py build
          • +
          • python setup.py install
          • +
          • python setup.py sdist
          • +
          +
        • +
        • EXTRA: install setuptools
            +
          • use: from setuptools import setup
          • +
          • try: `` python setup.py develop``
          • +
          +
        • +
        • EXTRA2: install wheel
            +
          • python setup.py bdist_wheel
          • +
          +
        • +
        +
        +

        (my example: Examples/Session09/capitalize)

        +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/python_for_linux.html b/supplements/python_for_linux.html new file mode 100644 index 00000000..7fa87598 --- /dev/null +++ b/supplements/python_for_linux.html @@ -0,0 +1,434 @@ + + + + + + + + + + + Setting Up Python For Linux — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Setting Up Python For Linux

        + + +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/python_for_mac.html b/supplements/python_for_mac.html new file mode 100644 index 00000000..6756f759 --- /dev/null +++ b/supplements/python_for_mac.html @@ -0,0 +1,329 @@ + + + + + + + + + + + Setting up your Mac for Python — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Setting up your Mac for Python

        +
        +

        Getting The Tools

        +

        OS-X comes with Python out of the box, but not the full setup you’ll need for development, and this class. It also doesn’t have the latest version(s), and no versino of Python 3.

        +

        So we recommend installing a new version.

        +

        Note:

        +

        If you use macports or homebrew to manage *nix software on your machine, feel free to use those for python, git, etc, as well. If not, then read on.

        +
        +

        Python

        +

        While OS-X does provide python out of the box – it tends not to have the +latest version, and you really don’t want to mess with the system +installation. So I recommend installing an independent installation from +python.org:

        +

        Download and install Python 3.4.3 64/32 bit installer from Python.org:

        +

        https://www.python.org/ftp/python/3.4.3/python-3.4.3-macosx10.6.pkg

        +

        (you can probably use 3.5.0, too, but it’s brand new, and there are a number of third party pacakges that are not yet available for it)

        +

        Simple as that.

        +

        Oddly, this does NOT install a python command, but rather a python3 command. If you want to be able to simply type python and get python3, then you can add a symlink to the install:

        +
        $ cd /Library/Frameworks/Python.framework/Versions/3.5/bin
        +$ ln -s python3.5 python
        +
        +
        +

        (or an alias in your shell – an Unix geeks here?)

        +
        +
        +

        Terminal

        +

        The built-in “terminal” application works fine. Find it in:

        +
        /Applications/Utilities/Terminal
        +
        +
        +

        Drag it to the dock to easy access.

        +
        +
        +

        git

        +

        Get a git client – the gitHub GUI client may be nice – I honestly don’t know.

        +

        There are a couple options for a command line client.

        +

        This one:

        +

        http://sourceforge.net/projects/git-osx-installer/

        +

        Is a big download and install, but has everything you need out of the box.

        +

        NOTE: if you get a warnign about it beign unsigned, you’ll need to go to yoru system preferences:

        +
        +

        “Security and Privacy”

        +

        Then check the box saying “Open Anyway”. Or maybe check the box saying you can install untrused pacakges – depends on the OS-X version

        +
        +

        This one:

        +

        http://git-scm.com/download/mac

        +

        Works great, but you need the XCode command line tools to run it. If you already have that, or expect to need a compiler anyway, then this is a good option.

        +

        You can get XCode from the Apple App Store.

        +

        (If you try running “git” on the command line after installing, it should send you there).

        +

        Warning: XCode is a BIG download. Once installed, run it so it can initialize itself.

        +

        After either of these is installed, the git command should work:

        +
        $ git --version
        +git version 1.8.5.2 (Apple Git-48)
        +
        +
        +
        +
        +

        pip

        +

        pip is the Python package installer. It is updated faster than python itself, so once you have python, you want to get the latest version of pip working:

        +
        $ python -m ensurepip --upgrade
        +
        +
        +

        [first make sure that python gives you the one you want. You may need to call python3 instead]

        +

        It should download and install the latest pip.

        +

        You can now use pip to install other packages.

        +
        +
        +

        iPython

        +

        One we are going to use in class is iPython:

        +
        $ python3 -m pip install ipython[all]
        +
        +
        +

        You should now be able to run iPython:

        +
        Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19)
        +Type "copyright", "credits" or "license" for more information.
        +
        +IPython 4.0.0 -- An enhanced Interactive Python.
        +?         -> Introduction and overview of IPython's features.
        +%quickref -> Quick reference.
        +help      -> Python's own help system.
        +object?   -> Details about 'object', use 'object??' for extra details.
        +
        +
        +
        +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/python_for_windows.html b/supplements/python_for_windows.html new file mode 100644 index 00000000..cdf6117e --- /dev/null +++ b/supplements/python_for_windows.html @@ -0,0 +1,312 @@ + + + + + + + + + + + Setting up Windows for Python — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Setting up Windows for Python

        +
        +

        Getting The Tools

        +
        +

        Python

        +

        There are a number of python distributions available – many designed for easier support of scientific programming:

        +
          +
        • Anaconda
        • +
        • Enthought Canopy
        • +
        • Python(x,y)
        • +
        +

        But for core use, the installer from python.org is the way to go:

        +

        https://www.python.org/downloads/

        +

        You want the installer for Python 3.x – probably 64 bit, though if you have a 32 bit sytem, you can get that. There is essentially no difference for the purposes of this course.

        +

        Double click and install.

        +
        +
        +

        Terminal

        +

        If you are confident in your use of the “DOS Box” or “powershell”, feel free to use one of those. However, your life may be easier if you install “Git Bash”, as then you can follow unix-style terminal instructions exactly, and do not have to translate. Also, your instructors are more experienced with Bash. +From now on, if you hear the terms ‘bash’, ‘shell’ or ‘terminal’, know that this is the application that is being referred to.

        +

        When you install Git Bash, you are installing git (and a git gui) as well, thus killing two birds with one stone, metaphorically speaking.

        +

        https://git-for-windows.github.io/

        +

        This is actually your best bet for running Python also – If you use the Git Bash shell, you can use the same commands as Linux and OS-X users. Regardless of which shell you choose, you will need to add Python to your environment. It is possible that this was done during the installation of python. If you type ‘which python’ into your terminal, and get back the answer ‘/c/python34/python’, then you are good to go, otherwise, follow the instructions here:

        +

        http://www.computerhope.com/issues/ch000549.htm

        +

        Based on the subversion of Python you will want to add something like:

        +

        C:\Python34

        +

        and

        +

        C:\Python34\Scripts

        +

        to PATH

        +
        +
        +

        git

        +

        If you installed Git Bash, you will already have git, both usable in the terminal and as a gui, and can safely skip this section. If not, you still need a git client. You can use the above link and install git (it will install the bash shell as well, of course, but you can use your shell of choice instead).

        +

        There is also TortoiseGit:

        +

        https://code.google.com/p/tortoisegit/

        +

        which integrates git with the file manager. Feel free to use this if you already have an understanding of how git works, but for the purposes of learning, it may be better to use a command line client (git Bash above).

        +
        +
        +

        pip

        +

        pip is the Python package installer. It is updated faster than python itself, so once you have python you want to get the latest version of pip working:

        +
        $ python -m ensurepip --upgrade
        +
        +
        +

        It should download and install the latest pip.

        +

        You can now use pip to install other packages.

        +
        +
        +

        iPython

        +

        One extra package we are going to use in class is iPython:

        +
        $ pip install ipython[all]
        +
        +
        +

        You should now be able to run iPython from the git bash shell:

        +
        $ ipython
        +    Python 2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35)
        +    Type "copyright", "credits" or "license" for more information.
        +
        +    IPython 2.0.0 -- An enhanced Interactive Python.
        +    ?         -> Introduction and overview of IPython's features.
        +    %quickref -> Quick reference.
        +    help      -> Python's own help system.
        +    object?   -> Details about 'object', use 'object??' for extra details.
        +
        +
        +

        (or from the DOS box or PowerShell prompt)

        +

        We will use this as our default python interpreter.

        +
        +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/python_learning_resources.html b/supplements/python_learning_resources.html new file mode 100644 index 00000000..872a1e6d --- /dev/null +++ b/supplements/python_learning_resources.html @@ -0,0 +1,354 @@ + + + + + + + + + + + Useful Python Learning Resources — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Useful Python Learning Resources

        +

        In addition to the material we cover in class, there are numerous online +resources to help a newcomer get to know Python. The following list represents +the best-known and best-regarded of the breed. If you are itching for a bit +more work on your Python chops, you should try these out.

        +
        +

        Python Language Resources

        +

        As a Python programmer, you’ll want to keep a bookmark pointed at the +official Python documentation (https://docs.python.org/3/), especially +the documentation for the standard library +(https://docs.python.org/3/library/index.html). However, there are a +number of additional resources you can (and should) use to help build +your Python chops.

        +
        +

        For the beginner

        +
          +
        • The Python Tutorial +(https://docs.python.org/3/tutorial/): This is the +official tutorial from the Python website. No more authoritative source is +available.
        • +
        • Code Academy Python Track +(http://www.codecademy.com/tracks/python): Often +cited as a great resource, this site offers an entertaining and engaging +approach and in-browser work.
        • +
        • Learn Python the Hard Way +(http://learnpythonthehardway.org/book/): Solid +and gradual. This course offers a great foundation for folks who have never +programmed in any language before.
        • +
        • Dive Into Python 3 +(http://www.diveintopython3.net/): The updated version +of a classic. This book offers an introduction to Python aimed at the student +who has experience programming in another language.
        • +
        • Python for You and Me +(http://pymbook.readthedocs.org/en/latest/): Simple +and clear. This is a great book for absolute newcomers, or to keep as a quick +reference as you get used to the language.
        • +
        • Think Python +(http://greenteapress.com/thinkpython/): Methodical and +complete. This book offers a very “computer science-style” introduction to +Python. It is really an intro to Python in the service of Computer Science, +though, so while helpful for the absolute newcomer, it isn’t quite as +“pythonic” as it might be.
        • +
        • Core Python Programming +(http://corepython.com/): Only available as a dead trees version, but +if you like to have book to hold in your hands anyway, this +is the best textbook style introduction out there. It starts from the +beginning, but gets into the full language. Published in 2009, but still in +print, with updated appendixes available for new language features.
        • +
        • Python 101 +(http://www.blog.pythonlibrary.org/2014/06/03/python-101-book-published-today/) +Available as a reasonably priced ebook. This is a new one from a popular Blogger +about Python. Lots of practical examples. Also avaiable as a Kindle book: +http://www.amazon.com/Python-101-Michael-Driscoll-ebook/dp/B00KQTFHNK
        • +
        +
        +
        +

        Next Steps

        +
          +
        • New Coder +(http://newcoder.io): Advertised as “Five lifejackets to throw to +the new coder”, this site offers five very interesting tutorials written in +an engaging style. Not an introduction. More a second step.
        • +
        • OpenHatch +(https://openhatch.org/wiki/Intermediate_Python_Workshop/Projects): +The Open Hatch project offers a number of workshops with well-paced +intermediate tutorials for Python programming. A great place to go once you +have the basics down and are ready for more challenging work.
        • +
        +
        +
        +

        Evaluating Your Options

        +

        The blurbs above are short descriptions of the material in each resource. We’ve +drawn them both from our own usage of the various tools, and from a wonderful +set of online reviews:

        +

        (http://planningadinner.blogspot.com/search/label/So%20you%20want%20to%20learn%20Python.%20What%27s%20next%3F)

        +

        done by Marta Maria Casetti on her blog, “Planning a Dinner” +(http://planningadinner.blogspot.com/).

        +

        The poster she presented at PyCon 2014 +(http://planningadinner.blogspot.com/2014/04/the-poster.html) +as a result of that research offers some great hints about the aspects of +Python programming best covered by each resource. I would urge any new student +of Python to take the time to look over this poster to help determine the best +path forward for themselves.

        +
        +
        +
        +

        iPython Interpreter Resources

        +

        iPython is an enhanced interpreter that makes interactive experimentation at the command line much more pleasant and powerful.

        + +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/shell.html b/supplements/shell.html new file mode 100644 index 00000000..394ee64e --- /dev/null +++ b/supplements/shell.html @@ -0,0 +1,400 @@ + + + + + + + + + + + Shell Customizations for Python Development — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Shell Customizations for Python Development

        +

        The command line is your home as a developer. You must be comfortable there. +In order to improve your comfort there are a number of enhancements you can +make to improve your experience, especially with non-standard software like +git and virtualenv

        +
        +

        What was that name, again?

        +

        For example, bash offers tab completion. But that doesn’t extend to +interactions with git. Considering how many branches, tags and remotes you +end up interacting with, and how many long-winded commands there are in +git, having a similar autocompletion for them would be very nice.

        +

        The folks who create such things have been kind enough to provide a shell +script that sets this up. And it’s not hard to install.

        +

        The script is called git-completion and it’s available in bash, +tcsh and zsh flavors.

        +

        To use it, download the version of the script that corresponds to your +preferred shell from the tag of the git repo that corresponds to the version of +git you are using. I’ve got git 1.8.4.2 installed on my machine, so +this is the version for me. Put it in your home directory:

        +
        $ cd
        +$ curl https://raw.github.com/git/git/v1.8.4.2/contrib/completion/git-completion.bash -o .git-completion.bash
        +
        +
        +

        Then source it from your shell startup file:

        +
        source ~/.git-completion.bash
        +
        +
        +

        There’s even a nifty gist that does this automatically for OS X.

        +

        Once installed, you should be able to visit any repository you have on your +machine and get tab completion of branch names, remotes and all git commands.

        +
        +
        +

        Where am I, what am I doing?

        +

        As a working developer, you end up with a lot of projects. Even with tab +completion its a chore to remember which branch is checked out, how far ahead +or behind the remote you are, and so on.

        +

        Enter git-prompt. Again, you place this code in your home directory, and +then source it from your shell startup file:

        +
        source ~/.git-prompt.sh
        +
        +
        +

        Once you do this you can use the __git_ps1 shell command and a number of +shell variables to configure PS1 and change your shell prompt. You can show +the name of the current branch of a repository when you are in one. You can +get information about the status of HEAD, modified files, stashes, untracked +files and more.

        +

        There’s two ways to do this. The first is to use __git_ps1 as a command +directly in a PS1 expression in your shell startup file:

        +
        export PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
        +
        +
        +

        The result looks like this:

        +Overriding PS1 provides a customized shell prompt +

        That’s not bad, but a bit of color would be nice, and perhaps breaking things +onto more than one line so you can parse what you’re seeing more easily would +be helpful.

        +

        For that, you’ll need to change strategies. The __git_ps1 command can be +used as a single element in the expression for PS1. But it can also be +used itself as the PROMPT_COMMAND env variable (this command is for +bash, there’s different one for zsh). If defined, this command will be +used to form PS1 dynamically.

        +

        When you use __git_ps1 in this way, a couple of things happen. First, +instead of taking only one optional argument (a format string), you can provide +two or optionally three arguments:

        +
          +
        • The first will be prepended to the output of the command
        • +
        • The second will be appended after
        • +
        • The optional third argumment will be used as a format string for the output +of the command itself. If there is no output, it will not appear at all.
        • +
        +

        Combining these three elements can be very expressive. For example, A standard +OS X command prompt can be expressed like so: \h:\W \u\\\$ ``. If you use this +expression as the second argument, leave the first empty and provide a simple format +ending in a newline for the ``__git_ps1 output, you get some nice results.

        +

        Enter this in your shell startup file:

        +
        PROMPT_COMMAND='__git_ps1 "" "\h:\W \u\\\$ " "[%s]\n"'
        +
        +
        +

        That produces a nice two-line prompt that appears when you’re in a git repo, and +disappears when you’re not:

        +A two-line prompt showing current git repository +

        You can also play with setting a few environment variables in your shell +startup file to expand this further. For example, colorizing the output and +providing information about the state of a repo:

        +
        GIT_PS1_SHOWDIRTYSTATE=1
        +GIT_PS1_SHOWCOLORHINTS=1
        +GIT_PS1_SHOWSTASHSTATE=1
        +GIT_PS1_SHOWUPSTREAM="auto"
        +PROMPT_COMMAND='__git_ps1 "" "\h:\W \u\\\$ " "[%s]\n"'
        +
        +
        +A colorized git prompt +

        Not half bad at all.

        +
        +
        +

        But wait, there’s more.

        +

        The problem with this is that it doesn’t play well with another incredibly +useful tool, virtualenv. When you activate a virtualenv, it prepends the name +of the environment you are working on to the shell prompt.

        +

        But it uses the standard PS1 shell variable to do this. Since you’ve now +used the PROMPT_COMMAND to create your prompt, PS1 is ignored, and +this nice feature of virtualenv is lost.

        +

        Luckily, there is a way out. Bash shell scripting offers parameter expansion +and a trick of the that syntax can help. Normally, a shell parameter is +referenced like so:

        +
        $ PARAM='foobar'
        +$ echo $PARAM
        +foobar
        +
        +
        +

        In complicated situations, you can wrap the name of the paramter in curly +braces to avoid confusion with following characters:

        +
        $ echo ${PARAM}andthennotparam
        +foobarandthennotparam
        +
        +
        +

        What is not as well known is that this curly-brace syntax has a lot of +interesting variations. For example, you can use PARAM as a test and +actually print something else entirely:

        +
        $ echo ${PARAM:+'foo'}
        +foo
        +$ echo ${PARAM:+'bar'}
        +
        +$
        +
        +
        +

        The key here is the :<char> bit immediately after PARAM. If the + +char is present, then if PARAM is unset or null, what comes after is not +printed, otherwise it is.

        +

        If you look at the script that activates a virtualenv in bash you’ll notice +that it exports VIRTUAL_ENV. This means that so long as a virtualenv is +active, this environmental variable will be set. And it will be unset when no +environment is active.

        +

        You can use that!

        +

        Armed with this knowledge, you can construct a shell expression that will either +print the name of the active virtualenv in square brackets, or print nothing if +no virtualenv was active:

        +
        $ echo ${VIRTUAL_ENV:+[`basename $VIRTUAL_ENV`]}
        +
        +$ source /path/to/someenv/bin/activate
        +$ echo ${VIRTUAL_ENV:+[`basename $VIRTUAL_ENV`]}
        +someenv
        +
        +
        +

        Roll that into your shell startup file. You’ll have everything you want. You +can even throw in a little more color for good measure:

        +
        source ~/.git-prompt.sh
        +# PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
        +GIT_PS1_SHOWDIRTYSTATE=1
        +GIT_PS1_SHOWCOLORHINTS=1
        +GIT_PS1_SHOWSTASHSTATE=1
        +GIT_PS1_SHOWUPSTREAM="auto"
        +Color_Off="\[\033[0m\]"
        +Yellow="\[\033[0;33m\]"
        +PROMPT_COMMAND='__git_ps1 "${VIRTUAL_ENV:+[$Yellow`basename $VIRTUAL_ENV`$Color_Off]\n}" "\h:\W \u\\\$ " "[%s]\n"'
        +
        +
        +

        And voilà! You’ve got a shell prompt that informs about all the things you’ll +need to know when working on a daily basis:

        +A shell session showing the prompt with both virtualenv and git information +
        +
        +

        Wrap-Up

        +

        There is still a great deal more that you could do with your shell, but this +will suffice for now. If you are interested in reading further, there is +a lot to learn.

        +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/sublime_as_ide.html b/supplements/sublime_as_ide.html new file mode 100644 index 00000000..cabab4eb --- /dev/null +++ b/supplements/sublime_as_ide.html @@ -0,0 +1,523 @@ + + + + + + + + + + + Turning Sublime Text Into a Lightweight Python IDE — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Turning Sublime Text Into a Lightweight Python IDE

        +

        A solid text editor is a developer’s best friend. You use it constantly and it +becomes like a second pair of hands. The keyboard commands you use daily +become so engrained in your muscle memory that you stop thinking about them +entirely.

        +

        With Sublime Text, it’s possible to turn your text editor into the functional +equivalent of a Python IDE. The best part is you don’t have to install an IDE +to do it.

        +
        +

        Requirements

        +

        Here are my requirements for an ‘IDE’:

        +
          +
        • It should provide excellent, configurable syntax colorization.
        • +
        • It should allow for robust tab completion.
        • +
        • It should offer the ability to jump to the definition of symbols in other +files.
        • +
        • It should perform automatic code linting to help avoid silly mistakes.
        • +
        • It should be able to interact with a Python interpreter such that when +debugging, the editor will follow along with the debugger.
        • +
        +
        +
        +

        Which Version?

        +

        While Version 3 is still considered “beta”, it is the one everyone is putting +their effort into, and some of the plugins I recommend are not available for +version 2.

        +
        +
        +

        Basic Settings

        +

        All configuration in Sublime Text is done via JSON. It’s simple to learn. go +and read that link then return here.

        +

        There are a number of different levels of configuration in Sublime Text. You +will most often work on settings at the user level.

        +

        Open Preferences -> Settings - Default to see all the default settings +and choose which to override.

        +

        Create your own set of preferences by opening Preferences -> Settings - +User. This will create an empty file, you can then copy the settings you want +to override from the default set into your personal settings.

        +

        Here’s a reasonable set of preliminary settings (theme, color scheme and font +are quite personal, find ones that suit you.):

        +
        source
        +
        +{
        +    "color_scheme": "Packages/User/Cobalt (SL).tmTheme",
        +    "theme": "Soda Light 3.sublime-theme",
        +    // A font face that helps distinguish between 0 (the number) and 'O' (the letter)
        +    // among other problem characters. YOu also want a "fixed width font"
        +    // Monaco is a nice option that comes with all Macs.
        +    // Not sure what's best on Windows.
        +    "font_face": "Monaco",
        +    // getting older. I wonder if comfy font size increases as a linear
        +    //  function of age?
        +    "font_size": 15,
        +    "ignored_packages":
        +    [
        +        // I'm not a vi user, so this is of no use to me.
        +        "Vintage"
        +    ],
        +    "rulers":
        +    [
        +        // set text rulers so I can judge line length for pep8
        +        72, // docstrings
        +        79, // optimum code line length
        +        100  // maximum allowable length
        +    ],
        +    "word_wrap": false, // I hate auto-wrapped text.
        +    "wrap_width": 79 // This is used by a plugin elsewhere
        +    "tab_size": 4,
        +    "translate_tabs_to_spaces": true,
        +    "use_tab_stops": true,
        +    "draw_white_space": "all", // I like so see spaces and tabs -- makes it easier to debug
        +}
        +
        +
        +

        Especially important is the setting translate_tabs_to_spaces, which ensures +that any time you hit a tab key, the single \t character is replaced by four +\s characters. In Python this is vital!

        +
        +
        +

        Extending the Editor

        +

        Most of the requirements above go beyond basic editor function. Use Plugins.

        +

        Sublime Text comes with a great system for Package Control. It handles +installing and uninstalling plugins, and even updates installed plugins for +you. You can also manually install plugins that haven’t made it to the big-time +yet, including ones you write yourself. Happily, the plugin system is +Python!

        +

        To install a plugin using Package Control, open the command palette with +shift-super-P (ctrl-shift-P on Windows/Linux). The super key is +command or on OS X. When the palette opens, typing install will +bring up the Package Control: Install Package command. Hit enter to +select it.

        +The package control command in the command palette. +

        After you select the command, Sublime Text fetches an updated list of packages +from the network. It might take a second or two for the list to appear. When it +does, start to type the name of the package you want. Sublime Text filters the +list and shows you what you want to see. To install a plugin, select it with +the mouse, or use arrow keys to navigate the list and hit enter when your +plugin is highlighted.

        +../_images/plugin_list.png +
        +
        +

        Useful Plugins

        +

        Here are the plugins I’ve installed to achieve the requirements above.

        +
        +

        Autocompletion

        +

        By default, Sublime Text will index symbols in open files and projects, but +that doesn’t cover installed python packages that may be part of a non-standard +run environment.

        +

        There are two to choose from:

        +
          +
        1. SublimeCodeIntel offers strong support for multiple languages through +it’s own plugin system. It is a bit heavy and requires building an index.
        2. +
        3. SublimeJedi only supports Python, but is faster and keeps an index on its +own.
        4. +
        +

        I’ve installed SublimeJedi, and used the following settings per project to +ensure that all relevant code is found:

        +
        {
        +    "folders":
        +    [
        +        // ...
        +    ],
        +
        +    "settings": {
        +        // ...
        +        "python_interpreter_path": "/Users/cewing/pythons/python-2.7/bin/python",
        +
        +        "python_package_paths": [
        +            "/path/to/project/buildout/parts/omelette"
        +        ]
        +    }
        +}
        +
        +
        +

        The python_interpreter_path allows me to indicate which Python executable +should be introspected for symbol definitions.

        +

        The python_package_paths setting allows designating additional paths that +will be searched for Python packages containing symbols.

        +Tab completion provided by SublimeJedi +

        Once configured, you should be able to use the ctrl-shift-G keyboard +shortcut to jump directly to the definition of a symbol. You can also use +alt-shift-F to find other usages of the same symbol elsewhere in your code.

        +
        +
        +

        Code Linting

        +

        Code linting shows you mistakes you’ve made in your source before you attempt +to run the code. This saves time. Sublime Text has an available plugin for code +linters called SublimeLinter.

        +

        Python has a couple of great tools available for linting, the pep8 and +pyflakes packages. Pep8 checks for style violations, lines too long, +extra spaces and so on. Pyflakes checks for syntactic violations, like +using a symbol that isn’t defined or importing a symbol you don’t use.

        +

        Another Python linting package, flake8 combines these two, and adds in +mccabe, a tool to check the cyclomatic complexity of code you write. This +can be of great help in discovering methods and functions that could be +simplified and thus made easier to understand and more testable.

        +

        There is a nice plugin for the SublimeLinter that utilizes flake8. For it to +work, the plugin will need to have a Python executable that has the Python +tools it needs installed.

        +

        Make sure that the python packages you need are installed in your main +python install, rather than a virtualenv.

        +

        Use Python packaging tools to install the required packages:

        +
        $ pip install flake8
        +Downloading/unpacking flake8
        +[...]
        +Downloading/unpacking pyflakes>=0.7.3 (from flake8)
        +[...]
        +Downloading/unpacking pep8>=1.4.6 (from flake8)
        +[...]
        +Downloading/unpacking mccabe>=0.2.1 (from flake8)
        +[...]
        +Installing collected packages: flake8, pyflakes, pep8, mccabe
        +[...]
        +Successfully installed flake8 pyflakes pep8 mccabe
        +Cleaning up...
        +$
        +
        +
        +

        Your Python install now has the required packages installed.

        +

        try typeing these command to make sure:

        +
        $ flake8
        +Usage: flake8 [options] input ...
        +
        +flake8: error: input not specified
        +
        +
        +

        Now install SublimeLinter and then SublimeLinter-flake8 using Package Control.

        +

        Here are the settings you can add to Preferences -> Package Settings -> +SublimeLinter -> Settings - User:

        +
        {
        +    //...
        +    "linters": {
        +        "flake8": {
        +            "@disable": false,
        +            "args": [],
        +            "builtins": "",
        +            "excludes": [],
        +            "ignore": "",
        +            "max-complexity": 10,
        +            "max-line-length": null,
        +            "select": ""
        +        }
        +    },
        +    //...
        +    "paths": {
        +        "linux": [],
        +        "osx": [
        +            "/Users/cewing/virtualenvs/sublenv/bin"
        +        ],
        +        "windows": []
        +    },
        +    "python_paths": {
        +        "linux": [],
        +        "osx": [
        +            "/Users/cewing/virtualenvs/sublenv/bin"
        +        ],
        +        "windows": []
        +    },
        +    //...
        +}
        +
        +
        +

        The paths key points to the path that contains the flake8 executable +command.

        +

        The python_paths key points to the location of the python executable to be +used.

        +

        The settings inside the flake8 object control the performance of the +linter. Read more about them here.

        +Flake8 shows unused import and trailing whitespace issues. +
        +
        +

        White Space Management

        +

        One of the issues highlighted by flake8 is trailing spaces. Sublime text +provides a setting that allows you to remove them every time you save a file:

        +
        source
        +
        +{
        +    "trim_trailing_whitespace_on_save": true
        +}
        +
        +
        +

        Do not use this setting

        +

        Removing trailing whitespace by default causes a ton of noise in commits.

        +

        Keep commits for stylistic cleanup separate from those that make important +changes to code.

        +

        The TrailingSpaces SublimeText plugin can help with this.

        +

        Here are the settings you can use:

        +
        {
        +    //...
        +    "trailing_spaces_modified_lines_only": true,
        +    "trailing_spaces_trim_on_save": true,
        +    // ...
        +}
        +
        +
        +

        This allows trimming whitespace on save, but only on lines you have directly +modified. You can still trim all whitespace manually and keep changesets +free of noise.

        +
        +
        +

        Follow-Along

        +

        The final requirement for a reasonable IDE experience is to be able to follow a +debugging session in the file where the code exists.

        +

        There is no plugin for SublimeText that supports this. But there is a Python +package you can install into the virtualenv for each of your projects that does +it.

        +

        The package is called PDBSublimeTextSupport and its simple to install with pip:

        +
        (projectenv)$ pip install PDBSublimeTextSupport
        +
        +
        +

        With that package installed in the Python that is used for your project, any +breakpoint you set will automatically pop to the surface in SublimeText. And +as you step through the code, you will see the current line in your Sublime +Text file move along with you.

        +
        +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/unicode.html b/supplements/unicode.html new file mode 100644 index 00000000..e435f085 --- /dev/null +++ b/supplements/unicode.html @@ -0,0 +1,642 @@ + + + + + + + + + + + Unicode — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Unicode

        +

        I hope you all read this:

        +

        The Absolute Minimum Every Software Developer Absolutely, +Positively Must Know About Unicode and Character Sets (No Excuses!)

        +

        http://www.joelonsoftware.com/articles/Unicode.html

        +

        If not – go read it!

        +
        +

        Fact number 1:

        +

        Everything is made up of bytes

        +

        If it’s on disk or transmitted over a network, it’s bytes

        +

        Python provides some abstractions to make it easier to deal with bytes

        +

        Unicode is a biggie

        +

        Actually, dealing with numbers rather than bytes is big – but we take that for granted

        +
        +
        +

        What the heck is Unicode anyway?

        +
          +
        • First there was chaos...
            +
          • Different machines used different encodings
          • +
          +
        • +
        • Then there was ASCII – and all was good (7 bit), 127 characters
            +
          • (for English speakers, anyway)
          • +
          +
        • +
        • But each vendor used the top half (127-255) for different things.
            +
          • macroman, Windows 1252, etc...
          • +
          • There is now “latin-1”, but still a lot of old files around
          • +
          +
        • +
        • Non Western-European languages required totally incompatible 1-byte +encodings
        • +
        • No way to mix languages with different alphabets.
        • +
        +
        +
        +

        Fact number 2:

        +

        The world needs more than 255 charactors.

        +

        Hello, world! • Здравствуй, мир!

        +

        Բարեւ, աշխարհի! • !مرحبا ، العالم

        +

        !שלום, עולם • 여보세요 세계!

        +

        नमस्ते, दुनिया! • 你好,世界!

        +
        +
        +

        Enter Unicode

        +

        The Unicode idea is pretty simple:

        +
        +
          +
        • one “code point” for all characters in all languages
        • +
        +
        +
        +
        But how do you express that in bytes?
        +
          +
        • Early days: we can fit all the code points in a two byte integer (65536 characters)
        • +
        • Turns out that didn’t work – we now need 32 bit integer to hold all of unicode +“raw” (UTC-4) – well we don’t need quite that many, but common machines don’t have +24 bit integers.
        • +
        +
        +
        Enter “encodings”:
        +
          +
        • An encoding is a way to map specific bytes to a code point.
        • +
        • Each code point can have one or more bytes.
        • +
        +
        +
        +
        +
        +
        +

        Mechanics

        +
        +

        What are strings?

        +

        Py2 strings are sequences of bytes

        +

        Unicode strings are sequences of platonic characters

        +

        It’s almost one code point per character – but there are complications +with combined characters: accents, etc. (we can ignore those most of the time)

        +

        Platonic characters cannot be written to disk or network!

        +

        (ANSI: one character == one byte – so easy!)

        +
        +
        +

        str vs unicode

        +

        Python 2 has two types that let you work with text:

        +
          +
        • str
        • +
        • unicode
        • +
        +

        And two ways to work with binary data:

        +
          +
        • str
        • +
        • bytes() (and bytearray)
        • +
        +

        but:

        +
        In [86]: str is bytes
        +Out[86]: True
        +
        +
        +

        bytes is there for py3 compatibility – but it’s good for making your +intentions clear, too.

        +
        +
        +

        Unicode

        +

        The unicode object lets you work with characters

        +

        It has all the same methods as the string object.

        +

        “encoding” is converting from a unicode object to bytes

        +

        “decoding” is converting from bytes to a unicode object

        +

        (sometimes this feels backwards...)

        +
        +
        +

        Using unicode in Py2

        +

        Built in functions

        +
        ord()
        +chr()
        +unichr()
        +str()
        +unicode()
        +
        +
        +

        The codecs module

        +
        import codecs
        +codecs.encode()
        +codecs.decode()
        +codecs.open() # better to use ``io.open``
        +
        +
        +
        +
        +

        Encoding and Decoding

        +

        Encoding

        +
        In [17]: u"this".encode('utf-8')
        +Out[17]: 'this'
        +
        +In [18]: u"this".encode('utf-16')
        +Out[18]: '\xff\xfet\x00h\x00i\x00s\x00'
        +
        +
        +

        Decoding

        +
        In [99]: print '\xff\xfe."+"x\x00\xb2\x00'.decode('utf-16')
        +∮∫x²
        +
        +
        +
        +
        +

        Unicode Literals

        +
          +
        1. Use unicode in your source files:
        2. +
        +
        # -*- coding: utf-8 -*-
        +
        +
        +
          +
        1. escape the unicode characters:
        2. +
        +
        print u"The integral sign: \u222B"
        +print u"The integral sign: \N{integral}"
        +
        +
        +

        Lots of tables of code points online:

        +
        +
        One example:
        +
        http://inamidst.com/stuff/unidata/
        +
        +

        hello_unicode.py.

        +
        +
        +

        Using Unicode

        +

        Use unicode objects in all your code

        +

        Decode on input

        +

        Encode on output

        +

        Many packages do this for you: XML processing, databases, ...

        +

        Gotcha:

        +

        Python has a default encoding (usually ascii)

        +
        In [2]: sys.getdefaultencoding()
        +Out[2]: 'ascii'
        +
        +
        +

        The default encoding will get used in unexpected places!

        +
        +
        +

        Using unicode everywhere

        +

        Python 2.6 and above have a nice feature to make it easier to use unicode everywhere

        +
        from __future__ import unicode_literals
        +
        +
        +

        After running that line, the u'' is assumed

        +
        In [1]: s = "this is a regular py2 string"
        +In [2]: print type(s)
        +<type 'str'>
        +
        +In [3]: from __future__ import unicode_literals
        +In [4]: s = "this is now a unicode string"
        +In [5]: type(s)
        +Out[5]: unicode
        +
        +
        +

        NOTE: You can still get py2 strings from other sources!

        +
        +
        +

        Encodings

        +

        What encoding should I use???

        +

        There are a lot:

        +

        http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings

        +

        But only a couple you are likely to need:

        +
          +
        • utf-8 (*nix)
        • +
        • utf-16 (Windows)
        • +
        +

        And of course, still the one-bytes ones.

        +
          +
        • ASCII
        • +
        • Latin-1
        • +
        +
        +
        +

        UTF-8

        +

        Probably the one you’ll use most – most common in Internet protocols (xml, JSON, etc.)

        +

        Nice properties:

        +
          +
        • ASCII compatible: first 127 characters are the same
        • +
        • Any ascii string is a utf-8 string
        • +
        • compact for mostly-english text.
        • +
        +

        Gotchas:

        +
          +
        • “higher” code points may use more than one byte: up to 4 for one character
        • +
        • ASCII compatible means in may work with default encoding in tests – but then blow up with real data...
        • +
        +
        +
        +

        UTF-16

        +

        Kind of like UTF-8, except it uses at least 16bits (2 bytes) for each character: not ASCII compatible.

        +

        But it still needs more than two bytes for some code points, so you still can’t assume two byte per character.

        +

        In C/C++ held in a “wide char” or “wide string”.

        +

        MS Windows uses UTF-16, as does (I think) Java.

        +
        +
        +

        UTF-16 criticism

        +

        There is a lot of criticism on the net about UTF-16 – it’s kind of the worst of both worlds:

        +
          +
        • You can’t assume every character is the same number of bytes
        • +
        • It takes up more memory than UTF-8
        • +
        +

        UTF-16 Considered Harmful

        +

        But to be fair:

        +

        Early versions of Unicode: everything fit into two bytes (65536 code points).

        +

        MS and Java were fairly early adopters, and it seemed simple enough to just use 2 bytes per character.

        +

        When it turned out that 4 bytes were really needed, they were kind of stuck in the middle.

        +
        +
        +

        Latin-1

        +

        NOT Unicode:

        +

        a 1-byte per char encoding.

        +
          +
        • Superset of ASCII suitable for Western European languages.
        • +
        • The most common one-byte-per-char encoding for European text.
        • +
        • Nice property – every byte value from 0 to 255 is a valid character ( at least in Python )
        • +
        +
          +
        • You will never get an UnicodeDecodeError if you try to decode arbitrary bytes with latin-1.
        • +
        • And it can “round-trip” through a unicode object.
        • +
        • Useful if you don’t know the encoding – at least it won’t raise an Exception
        • +
        • Useful if you need to work with combined text+binary data.
        • +
        +

        latin1_test.py.

        +
        +
        +

        Unicode Docs

        +

        Python Docs Unicode HowTo:

        +

        http://docs.python.org/howto/unicode.html

        +

        “Reading Unicode from a file is therefore simple”

        +
        import io
        +f = io.open('hello_unicode.py', encoding='utf-8')
        +for line in f:
        +    print repr(line)
        +
        +
        +
        +
        Encodings Built-in to Python:
        +
        http://docs.python.org/2/library/codecs.html#standard-encodings
        +
        +
        +
        +

        Gotchas in Python 2

        +

        file names, etc:

        +

        If you pass in unicode, you get unicode

        +
        In [9]: os.listdir('./')
        +Out[9]: ['hello_unicode.py', 'text.utf16', 'text.utf32']
        +
        +In [10]: os.listdir(u'./')
        +Out[10]: [u'hello_unicode.py', u'text.utf16', u'text.utf32']
        +
        +
        +

        Python deals with the file system encoding for you...

        +

        But: some more obscure calls don’t support unicode filenames:

        +

        os.statvfs() (http://bugs.python.org/issue18695)

        +

        Exception messages:

        +
        +
          +
        • Py2 Exceptions use str when they print messages.
        • +
        • But what if you pass in a unicode object?
            +
          • It is encoded with the default encoding.
          • +
          +
        • +
        • UnicodeDecodeError Inside an Exception????
        • +
        +

        NOPE: it swallows it instead.

        +
        +

        unicode_exception_test.py.

        +
        +
        +

        Unicode in Python 3

        +

        The “string” object is unicode.

        +

        Py3 has two distinct concepts:

        +
          +
        • “text” – uses the str object (which is always unicode!)
        • +
        • “binary data” – uses bytes or bytearray
        • +
        +

        Everything that’s about text is unicode.

        +

        Everything that requires binary data uses bytes.

        +

        It’s all much cleaner.

        +

        (by the way, the recent implementations are very efficient...)

        +
        +
        +
        +

        Basic Unicode LAB

        +
          +
        • Find some nifty non-ascii characters you might use.
            +
          • Create a unicode object with them in two different ways.
          • +
          • here is one example
          • +
          +
        • +
        • Read the contents into unicode objects:
        • +
        +
        +
        +

        and/ or

        +
        +
        +
          +
        • write some of the text from the first exercise to file – read that +file back in.
        • +
        +

        Reference: http://inamidst.com/stuff/unidata/

        +

        NOTE: if your terminal does not support unicode – you’ll get an error trying +to print. Try a different terminal or IDE, or google for a solution.

        +
        +

        Challenge Unicode LAB

        +

        We saw this earlier

        +
        In [38]: u'to \N{INFINITY} and beyond!'.decode('utf-8')
        +---------------------------------------------------------------------------
        +UnicodeEncodeError                        Traceback (most recent call last)
        +<ipython-input-38-7f87d44dfcfa> in <module>()
        +----> 1 u'to \N{INFINITY} and beyond!'.decode('utf-8')
        +
        +/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.pyc in decode(input, errors)
        +     14
        +     15 def decode(input, errors='strict'):
        +---> 16     return codecs.utf_8_decode(input, errors, True)
        +     17
        +     18 class IncrementalEncoder(codecs.IncrementalEncoder):
        +
        +UnicodeEncodeError: 'ascii' codec can't encode character u'\u221e' in position 3: ordinal not in range(128)
        +
        +
        +

        But why would you decode a unicode object?

        +

        And it should be a no-op – why the exception?

        +

        And why ‘ascii’? I specified ‘utf-8’!

        +

        It’s there for backward compatibility

        +

        What’s happening under the hood:

        +
        u'to \N{INFINITY} and beyond!'.encode().decode('utf-8')
        +
        +
        +

        It encodes with the default encoding (ascii), then decodes

        +

        In this case, it barfs on attempting to encode to ‘ascii’

        +

        So never call decode on a unicode object!

        +

        But what if someone passes one into a function of yours that’s expecting +a py2 string?

        +

        Type checking and converting – yeach!

        +

        Read:

        +

        http://axialcorps.com/2014/03/20/unicode-str/

        +

        See if you can figure out the decorators:

        +

        unicodify.py.

        +

        (This is advanced Python JuJu: Aren’t you glad I didn’t ask you to write +that yourself?)

        +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/unicode2.html b/supplements/unicode2.html new file mode 100644 index 00000000..54b99a67 --- /dev/null +++ b/supplements/unicode2.html @@ -0,0 +1,599 @@ + + + + + + + + + + + Unicode — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +

        Antoher verison os the Unicode discussion – I htink there is a bit in here that we’ll want to use.

        +
        +

        Unicode

        +

        I hope you all read this:

        +

        The Absolute Minimum Every Software Developer Absolutely, +Positively Must Know About Unicode and Character Sets (No Excuses!)

        +

        http://www.joelonsoftware.com/articles/Unicode.html

        +

        If not – go read it!

        +
        +

        Fact number 1:

        +

        Everything is made up of bytes

        +

        If it’s on disk or transmitted over a network, it’s bytes

        +

        Python provides some abstractions to make it easier to deal with bytes

        +

        Unicode is a biggie

        +

        Actually, dealing with numbers rather than bytes is big – but we take that for granted

        +
        +
        +

        What the heck is Unicode anyway?

        +
          +
        • First there was chaos...
            +
          • Different machines used different encodings
          • +
          +
        • +
        • Then there was ASCII – and all was good (7 bit), 127 characters
            +
          • (for English speakers, anyway)
          • +
          +
        • +
        • But each vendor used the top half (127-255) for different things.
            +
          • macroman, Windows 1252, etc...
          • +
          • There is now “latin-1”, but still a lot of old files around
          • +
          +
        • +
        • Non Western-European languages required totally incompatible 1-byte +encodings
        • +
        • No way to mix languages with different alphabets.
        • +
        +
        +
        +

        Fact number 2:

        +

        The world needs more than 255 charactors.

        +

        Hello, world! • Здравствуй, мир!

        +

        Բարեւ, աշխարհի! • !مرحبا ، العالم

        +

        !שלום, עולם • 여보세요 세계!

        +

        नमस्ते, दुनिया! • 你好,世界!

        +
        +
        +

        Enter Unicode

        +

        The Unicode idea is pretty simple:

        +
        +
          +
        • one “code point” for all characters in all languages
        • +
        +
        +
        +
        But how do you express that in bytes?
        +
          +
        • Early days: we can fit all the code points in a two byte integer (65536 characters)
        • +
        • Turns out that didn’t work – we now need 32 bit integer to hold all of unicode +“raw” (UTC-4) – well we dopnt need that many, but common machines don’t have +24 bit integers.
        • +
        +
        +
        Enter “encodings”:
        +
          +
        • An encoding is a way to map specific bytes to a code point.
        • +
        • Each code point can have one or more bytes.
        • +
        +
        +
        +
        +
        +
        +

        Mechanics

        +
        +

        What are strings?

        +

        Py2 strings are sequences of bytes

        +

        Unicode strings are sequences of platonic characters

        +

        It’s almost one code point per character – but there are complications +with combined characters: accents, etc. (we can ignore those most of the time)

        +

        Platonic characters cannot be written to disk or network!

        +

        (ANSI: one character == one byte – so easy!)

        +
        +
        +

        str vs unicode

        +

        Python 2 has two types that let you work with text:

        +
          +
        • str
        • +
        • unicode
        • +
        +

        And two ways to work with binary data:

        +
          +
        • str
        • +
        • bytes() (and bytearray)
        • +
        +

        but:

        +
        In [86]: str is bytes
        +Out[86]: True
        +
        +
        +

        bytes is there for py3 compatibility – but it’s good for making your +intentions clear, too.

        +
        +
        +

        Unicode

        +

        The unicode object lets you work with characters

        +

        It has all the same methods as the string object.

        +

        “encoding” is converting from a unicode object to bytes

        +

        “decoding” is converting from bytes to a unicode object

        +

        (sometimes this feels backwards...)

        +
        +
        +

        Using unicode in Py2

        +

        Built in functions

        +
        ord()
        +chr()
        +unichr()
        +str()
        +unicode()
        +
        +
        +

        The codecs module

        +
        import codecs
        +codecs.encode()
        +codecs.decode()
        +codecs.open() # better to use ``io.open``
        +
        +
        +
        +
        +

        Encoding and Decoding

        +

        Encoding

        +
        In [17]: u"this".encode('utf-8')
        +Out[17]: 'this'
        +
        +In [18]: u"this".encode('utf-16')
        +Out[18]: '\xff\xfet\x00h\x00i\x00s\x00'
        +
        +
        +

        Decoding

        +
        In [99]: print '\xff\xfe."+"x\x00\xb2\x00'.decode('utf-16')
        +∮∫x²
        +
        +
        +
        +
        +

        Unicode Literals

        +
          +
        1. Use unicode in your source files:
        2. +
        +
        # -*- coding: utf-8 -*-
        +
        +
        +
          +
        1. escape the unicode characters:
        2. +
        +
        print u"The integral sign: \u222B"
        +print u"The integral sign: \N{integral}"
        +
        +
        +

        Lots of tables of code points online:

        +
        +
        One example:
        +
        http://inamidst.com/stuff/unidata/
        +
        +

        hello_unicode.py.

        +
        +
        +

        Using Unicode

        +

        Use unicode objects in all your code

        +

        Decode on input

        +

        Encode on output

        +

        Many packages do this for you: XML processing, databases, ...

        +

        Gotcha:

        +

        Python has a default encoding (usually ascii)

        +
        In [2]: sys.getdefaultencoding()
        +Out[2]: 'ascii'
        +
        +
        +

        The default encoding will get used in unexpected places!

        +
        +
        +

        Using unicode everywhere

        +

        Python 2.6 and above have a nice feature to make it easier to use unicode everywhere

        +
        from __future__ import unicode_literals
        +
        +
        +

        After running that line, the u'' is assumed

        +
        In [1]: s = "this is a regular py2 string"
        +In [2]: print type(s)
        +<type 'str'>
        +
        +In [3]: from __future__ import unicode_literals
        +In [4]: s = "this is now a unicode string"
        +In [5]: type(s)
        +Out[5]: unicode
        +
        +
        +

        NOTE: You can still get py2 strings from other sources!

        +
        +
        +

        Encodings

        +

        What encoding should I use???

        +

        There are a lot:

        +

        http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings

        +

        But only a couple you are likely to need:

        +
          +
        • utf-8 (*nix)
        • +
        • utf-16 (Windows)
        • +
        +

        And of course, still the one-bytes ones.

        +
          +
        • ASCII
        • +
        • Latin-1
        • +
        +
        +
        +

        UTF-8

        +

        Probably the one you’ll use most – most common in Internet protocols (xml, JSON, etc.)

        +

        Nice properties:

        +
          +
        • ASCII compatible: first 127 characters are the same
        • +
        • Any ascii string is a utf-8 string
        • +
        • compact for mostly-english text.
        • +
        +

        Gotchas:

        +
          +
        • “higher” code points may use more than one byte: up to 4 for one character
        • +
        • ASCII compatible means in may work with default encoding in tests – but then blow up with real data...
        • +
        +
        +
        +

        UTF-16

        +

        Kind of like UTF-8, except it uses at least 16bits (2 bytes) for each character: not ASCII compatible.

        +

        But it still needs more than two bytes for some code points, so you still can’t assume two byte per character.

        +

        In C/C++ held in a “wide char” or “wide string”.

        +

        MS Windows uses UTF-16, as does (I think) Java.

        +
        +
        +

        UTF-16 criticism

        +

        There is a lot of criticism on the net about UTF-16 – it’s kind of the worst of both worlds:

        +
          +
        • You can’t assume every character is the same number of bytes
        • +
        • It takes up more memory than UTF-8
        • +
        +

        UTF-16 Considered Harmful

        +

        But to be fair:

        +

        Early versions of Unicode: everything fit into two bytes (65536 code points).

        +

        MS and Java were fairly early adopters, and it seemed simple enough to just use 2 bytes per character.

        +

        When it turned out that 4 bytes were really needed, they were kind of stuck in the middle.

        +
        +
        +

        Latin-1

        +

        NOT Unicode:

        +

        a 1-byte per char encoding.

        +
          +
        • Superset of ASCII suitable for Western European languages.
        • +
        • The most common one-byte per char encoding for European text.
        • +
        • Nice property – every byte value from 0 to 255 is a valid character ( at least in Python )
        • +
        +
          +
        • You will never get an UnicodeDecodeError if you try to decode arbitrary bytes with latin-1.
        • +
        • And it can “round-trip” through a unicode object.
        • +
        • Useful if you don’t know the encoding – at least it won’t raise an Exception
        • +
        • Useful if you need to work with combined text+binary data.
        • +
        +

        latin1_test.py.

        +
        +
        +

        Unicode Docs

        +

        Python Docs Unicode HowTo:

        +

        http://docs.python.org/howto/unicode.html

        +

        “Reading Unicode from a file is therefore simple”

        +
        import io
        +f = io.open('hello_unicode.py', encoding='utf-8')
        +for line in f:
        +    print repr(line)
        +
        +
        +
        +
        Encodings Built-in to Python:
        +
        http://docs.python.org/2/library/codecs.html#standard-encodings
        +
        +
        +
        +

        Gotchas in Python 2

        +

        file names, etc:

        +

        If you pass in unicode, you get unicode

        +
        In [9]: os.listdir('./')
        +Out[9]: ['hello_unicode.py', 'text.utf16', 'text.utf32']
        +
        +In [10]: os.listdir(u'./')
        +Out[10]: [u'hello_unicode.py', u'text.utf16', u'text.utf32']
        +
        +
        +

        Python deals with the file system encoding for you...

        +

        But: some more obscure calls don’t support unicode filenames:

        +

        os.statvfs() (http://bugs.python.org/issue18695)

        +

        Exception messages:

        +
        +
          +
        • Py2 Exceptions use str when they print messages.
        • +
        • But what if you pass in a unicode object?
            +
          • It is encoded with the default encoding.
          • +
          +
        • +
        • UnicodeDecodeError Inside an Exception????
        • +
        +

        NOPE: it swallows it instead.

        +
        +

        unicode_exception_test.py.

        +
        +
        +

        Unicode in Python 3

        +

        The “string” object is unicode.

        +

        Py3 has two distinct concepts:

        +
          +
        • “text” – uses the str object (which is always unicode!)
        • +
        • “binary data” – uses bytes or bytearray
        • +
        +

        Everything that’s about text is unicode.

        +

        Everything that requires binary data uses bytes.

        +

        It’s all much cleaner.

        +

        (by the way, the recent implementations are very efficient...)

        +
        +
        +
        +

        Basic Unicode LAB

        +
          +
        • Find some nifty non-ascii characters you might use.
            +
          • Create a unicode object with them in two different ways.
          • +
          • here is one example
          • +
          +
        • +
        • Read the contents into unicode objects:
        • +
        +
        +
        +

        and/ or

        +
        +
        +
          +
        • write some of the text from the first exercise to file – read that +file back in.
        • +
        +

        Reference: http://inamidst.com/stuff/unidata/

        +

        NOTE: if your terminal does not support unicode – you’ll get an error trying +to print. Try a different terminal or IDE, or google for a solution.

        +
        +

        Challenge Unicode LAB

        +

        We saw this earlier

        +
        In [38]: u'to \N{INFINITY} and beyond!'.decode('utf-8')
        +---------------------------------------------------------------------------
        +UnicodeEncodeError                        Traceback (most recent call last)
        +<ipython-input-38-7f87d44dfcfa> in <module>()
        +----> 1 u'to \N{INFINITY} and beyond!'.decode('utf-8')
        +
        +/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.pyc in decode(input, errors)
        +     14
        +     15 def decode(input, errors='strict'):
        +---> 16     return codecs.utf_8_decode(input, errors, True)
        +     17
        +     18 class IncrementalEncoder(codecs.IncrementalEncoder):
        +
        +UnicodeEncodeError: 'ascii' codec can't encode character u'\u221e' in position 3: ordinal not in range(128)
        +
        +
        +

        But why would you decode a unicode object?

        +

        And it should be a no-op – why the exception?

        +

        And why ‘ascii’? I specified ‘utf-8’!

        +

        It’s there for backward compatibility

        +

        What’s happening under the hood:

        +
        u'to \N{INFINITY} and beyond!'.encode().decode('utf-8')
        +
        +
        +

        It encodes with the default encoding (ascii), then decodes

        +

        In this case, it barfs on attempting to encode to ‘ascii’

        +

        So never call decode on a unicode object!

        +

        But what if someone passes one into a function of yours that’s expecting +a py2 string?

        +

        Type checking and converting – yeach!

        +

        Read:

        +

        http://axialcorps.com/2014/03/20/unicode-str/

        +

        See if you can figure out the decorators:

        +

        unicodify.py.

        +

        (This is advanced Python JuJu: Aren’t you glad I didn’t ask you to write +that yourself?)

        +
        +
        + + +
        +
        +
        + + +
        + +
        +

        + © Copyright 2014, Christopher Barker, Cris Ewing, . + +

        +
        + Built with Sphinx using a theme provided by Read the Docs. + +
        + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/supplements/virtualenv.html b/supplements/virtualenv.html new file mode 100644 index 00000000..8ae7db7b --- /dev/null +++ b/supplements/virtualenv.html @@ -0,0 +1,589 @@ + + + + + + + + + + + Working with Virtualenv — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        Working with Virtualenv

        +

        “For every non-standard package installed in a system Python, the gods kill a +kitten”

        +
          +
        • me
        • +
        +
        +

        Reasons Why

        +
          +
        • As a working developer you will need to install packages that aren’t in the +Python standard Library
        • +
        • As a working developer you often need to install different versions of the +same library for different projects
        • +
        • Conflicts arising from having the wrong version of a dependency installed can +cause long-term nightmares
        • +
        • Use virtualenv ...
        • +
        • Always
        • +
        +
        +

        Installing Virtualenv

        +

        The best way is to install directly in your system Python (one exception to the +rule).

        +

        To do so you will have to have pip installed.

        +

        Try the following command:

        +
        $ which pip
        +/usr/local/bin/pip
        +
        +
        +

        If the which command returns no value for you, then pip is not +installed in your system. To fix this, follow the instructions here.

        +

        Once you have pip installed in your system, you can use it to install +virtualenv. Because you are installing it into your system python, you will +most likely need superuser privileges to do so:

        +
        $ sudo pip install virtualenv
        +Downloading/unpacking virtualenv
        +  Downloading virtualenv-1.11.2-py2.py3-none-any.whl (2.8MB): 2.8MB downloaded
        +Installing collected packages: virtualenv
        +Successfully installed virtualenv
        +Cleaning up...
        +
        +
        +

        Great. Once that’s done, you should find that you have a virtualenv +command available to you from your shell:

        +
        $ virtualenv --help
        +Usage: virtualenv [OPTIONS] DEST_DIR
        +
        +Options:
        +  --version             show program's version number and exit
        +  -h, --help            ...
        +
        +
        +
        +
        +
        +

        Using Virtualenv

        +

        Creating a new virtualenv is very very simple:

        +
        $ virtualenv [options] <ENV>
        +
        +
        +

        <ENV> is just the name of the environment you want to create. It’s +arbitrary. Let’s make one for demonstration purposes:

        +
        $ virtualenv demoenv
        +New python executable in demoenv/bin/python
        +Installing setuptools, pip...done.
        +
        +
        +
        +

        What Happened?

        +

        When you ran that command, a couple of things took place:

        +
          +
        • A new directory with your requested name was created
        • +
        • A new Python executable was created in <ENV>/bin (<ENV>/Scripts on Windows)
        • +
        • The new Python was cloned from your system Python (where virtualenv was +installed)
        • +
        • The new Python was isolated from any libraries installed in the old Python
        • +
        • Setuptools was installed so you have easy_install for this new python
        • +
        • Pip was installed so you have pip for this new python
        • +
        +
        +
        +

        Activation

        +

        The virtual environment you just created, demoenv contains an executable +Python command, but if you do a quick check to see which Python executable is +found by your terminal, you’ll see that it is not the one:

        +
        $ which python
        +/usr/bin/python
        +
        +
        +

        You can execute the new Python by explicitly pointing to it:

        +
        $ ./demoenv/bin/python -V
        +Python 2.7.5
        +
        +
        +

        but that’s tedious and hard to remember. Instead, activate your virtualenv +using the source command:

        +
        $ source demoenv/bin/activate
        +(demoenv)$ which python
        +/Users/cewing/demoenv/bin/python
        +
        +
        +

        There. That’s better. Now whenever you run the python command, the +executable that will be used will be the new one in your demoenv.

        +

        Notice also that the your shell prompt has changed. It indicates which +virtualenv is currently active. Little clues like that really help you to +keep things straight when you’ve got a lot of projects going on, so it’s nice +the makers of virtualenv thought of it.

        +
        +
        +

        Installing Packages

        +

        Now that your virtualenv is active, not only has your python executable been +hijacked, so have pip and easy_install:

        +
        (demoenv)$ which pip
        +/Users/cewing/demoenv/bin/pip
        +(demoenv)$ which easy_install
        +/Users/cewing/demoenv/bin/easy_install
        +
        +
        +

        This means that using these tools to install packages will install them into +your virtual environment only and not into the system Python. Let’s see this +in action. We’ll install a package called docutils that provides support +for converting ReStructuredText documents into other formats like HTML, LaTeX +and more:

        +
        (demoenv)$ pip install docutils
        +Downloading/unpacking docutils
        +  Downloading docutils-0.11.tar.gz (1.6MB): 1.6MB downloaded
        +  Running setup.py (path:/Users/cewing/demoenv/build/docutils/setup.py) egg_info for package docutils
        +    ...
        +    changing mode of /Users/cewing/demoenv/bin/rst2xml.py to 755
        +    changing mode of /Users/cewing/demoenv/bin/rstpep2html.py to 755
        +Successfully installed docutils
        +Cleaning up...
        +
        +
        +

        And now, when we fire up our Python interpreter, the docutils package is +available to us:

        +
        (demoenv)$ python
        +Python 2.7.5 (default, Aug 25 2013, 00:04:04)
        +[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
        +Type "help", "copyright", "credits" or "license" for more information.
        +>>> import docutils
        +>>> docutils.__path__
        +['/Users/cewing/demoenv/lib/python2.7/site-packages/docutils']
        +>>> ^d
        +(demoenv)$
        +
        +
        +

        There’s one other interesting side-effect of installing software with +virtualenv. The docutils package provides a number of executable +scripts when it is installed: rst2html.py, rst2latex.py and so on. +These scripts are set up to execute using the Python with which they were +built. What this means is that running these scripts will use the Python +executable in your virtualenv, even if that virtualenv is not active!

        +
        +
        +

        Deactivation

        +

        So you’ve got a virtual environment created. And you’ve activated it so that +you can install packages and use them. Eventually you’ll need to move on to +some other project. This likely means that you’ll need to stop working with +this virtualenv and switch to another (it’s a good idea to keep a separate +virtualenv for every project you work on).

        +

        When a virtualenv is active, all you have to do is use the deactivate +command:

        +
        (demoenv)$ deactivate
        +$ which python
        +/usr/bin/python
        +
        +
        +

        Note that your shell prompt returns to normal, and now the executable Python +found when you check python is the system one again.

        +
        +
        +

        Cleaning Up

        +

        The final great advantage that virtualenv confers on you as a developer is +the ability to easily remove a batch of installed Python software from your +system. Consider a situation where you installed a library that breaks your +Python (it happens). If you are working in your system Python, you now have to +figure out what that package installed, where, and go clean it out manually. +With virtualenv the process is as simple as removing the directory that +virtualenv created when you started out. Let’s do that with our demoenv:

        +
        $ rm -rf demoenv
        +
        +
        +

        And that’s it. The entire environment and all the packages you installed into +it are now gone. There’s no traces left to pollute your world.

        +
        +

        VirtualenvWrapper

        +

        So you have this great tool that allows you to build isolated environments in +which you can install Python software. Several questions arise when considering +this.

        +
          +
        • Where should such environments be placed?
        • +
        • How can the environments be tied to the projects you are working on?
        • +
        • Once you have more than a trivial number of projects, how can you keep track +of all these virtualenvs?
        • +
        +

        Like any good tool, virtualenv does not impose on you any particular way of +working. You can place your environments into the directories where you are +building the project to which they apply. You can keep them all in a single +global location. You can build a random path generator that drops them +wherever.

        +

        But any of these methods lead inevetably to chaos. They require too much from +you. It would be better if you could manage your virtual environments easily +and intuitively.

        +

        With virtualenvwrapper you can.

        +
        +
        +
        +

        Installation

        +

        Let’s start by installing the package in our system Python, alongside +virtualenv (again, you’ll need superuser to do this):

        +
        $ sudo pip install virtualenvwrapper
        +Downloading/unpacking virtualenvwrapper
        +  Downloading virtualenvwrapper-4.2.tar.gz (125kB): 125kB downloaded
        +  Running setup.py (path:/private/tmp/pip_build_root/virtualenvwrapper/setup.py) egg_info for package virtualenvwrapper
        +  ...
        +Successfully installed virtualenvwrapper virtualenv-clone stevedore
        +Cleaning up...
        +$
        +
        +
        +

        Once that’s finished, you’ll need to wire the system up by letting your shell +know that the commands it provides are present. Add the following lines to your +shell startup file (.profile, .bash-profile, ...):

        +
        export WORKON_HOME=~/.virtualenvs
        +source /usr/local/bin/virtualenvwrapper.sh
        +
        +
        +

        This will create a new environmental variable, WORKON_HOME, that determines +where new virtual environments will be created. The actual name is completely +arbitrary.

        +

        You’ll need to be sure that the location you set exists:

        +
        $ mkdir ~/.virtualenvs
        +
        +
        +
        +
        +

        Using mkvirtualenv

        +

        When you’ve done that, start a new terminal and you’ll have access to the +mkvirtualenv command:

        +
        $ mkvirtualenv testenv
        +New python executable in testenv/bin/python
        +Installing setuptools, pip...done.
        +(testenv)$ ls ~/.virtualenvs
        +testenv
        +(testenv)$ which python
        +/Users/cewing/.virtualenvs/testenv/bin/python
        +(testenv)$
        +
        +
        +

        Notice a couple of things:

        +
          +
        • The new environment you asked for was created in WORKON_HOME
        • +
        • The new environment was immedately activated for you
        • +
        +

        That’s a nice feature, eh? No more needing to remember to activate the env +you just created to install packages.

        +
        +
        +

        Using workon

        +

        In addition to this nice little feature, you can also use the workon +command to see which environments you have, and to switch from one to another:

        +
        (testenv)$ workon
        +testenv
        +(testenv)$ mkvirtualenv number2
        +New python executable in number2/bin/python
        +Installing setuptools, pip...done.
        +(number2)$ workon
        +number2
        +testenv
        +(number2)$ workon testenv
        +(testenv)$
        +
        +
        +

        Sweet!

        +

        The same deactivate command can get you back to your system environment:

        +
        (testenv)$ deactivate
        +$
        +
        +
        +
        +
        +

        Using mkproject

        +

        That takes care of deciding where to put new environments. It also clears up +the question of how to remember which ones you have and how to start them up +and switch between them. But we still have to figure out how to remember which +environment goes with which project.

        +

        That’s what the mkproject command is for.

        +

        First, go back to your shell startup file and add a new environmental variable:

        +
        export PROJECT_HOME=~/projects #<- this line here is new
        +export WORKON_HOME=~/.virtualenvs
        +source /usr/local/bin/virtualenvwrapper.sh
        +
        +
        +

        Then, make sure the directory you named exists:

        +
        $ mkdir ~/projects
        +
        +
        +

        After all that, fire up a new shell to pick up the changes and try this:

        +
        $ mkproject foo
        +New python executable in foo/bin/python
        +Installing setuptools, pip...done.
        +Creating /Users/cewing/projects/foo
        +Setting project for foo to /Users/cewing/projects/foo
        +(foo)$ which python
        +/Users/cewing/.virtualenvs/foo/bin/python
        +(foo)$ pwd
        +/Users/cewing/projects/foo
        +(foo)$ ls -a $VIRTUAL_ENV
        +.       .Python     bin     lib
        +..      .project    include
        +(foo)$ more $VIRTUAL_ENV/.project
        +/Users/cewing/projects/foo
        +
        +
        +

        Whoa! That command did a lot:

        +
          +
        • Created a new virtualenv in your $WORKON_HOME
        • +
        • Created a new project directory in your $PROJECT_HOME
        • +
        • Placed a .project file in your home directory with a path leading to the +associated project directory
        • +
        • Activated the new virtualenv for you
        • +
        • Automatically moved your present working directory to the new project +directory.
        • +
        +

        And now, you can begin working on your foo project, secure that you will be +installing packages into the right environment.

        +
        +

        A Few Last Words

        +

        This quick introduction is by no means an exhaustive manual for either of +the packages we’ve talked about. There is a great deal more that they can do. +In particular, virtualenvwrapper is highly customizable, with support for +custom scripts to be hooked into every stage of the virtualenv workflow.

        +

        I urge you to read the documentation for virtualenv and virtualenvwrapper +yourself to find out more.

        +
        +
        +
        +
        + + +
        +
        + + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/unused_stuff.html b/unused_stuff.html new file mode 100644 index 00000000..55670a14 --- /dev/null +++ b/unused_stuff.html @@ -0,0 +1,225 @@ + + + + + + + + + + + switch? — Introduction To Python 1.3 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
        + + + + + + +
        +
        + + + + + + +
        + +
        +
        +
        +
        + +
        +

        switch?

        +

        Many languages have a switch construct:

        +
        switch (expr) {
        +  case "Oranges":
        +    document.write("Oranges are $0.59 a pound.<br>");
        +    break;
        +  case "Apples":
        +    document.write("Apples are $0.32 a pound.<br>");
        +    break;
        +  case "Mangoes":
        +  case "Papayas":
        +    document.write("Mangoes and papayas are $2.79 a pound.<br>");
        +    break;
        +  default:
        +    document.write("Sorry, we are out of " + expr + ".<br>");
        +}
        +
        +
        +

        Not Python

        +

        use if..elif..elif..else

        +

        (or a dictionary, or subclassing....)

        +
        + + +
        +
        +
        + + +
        + +
        +

        + © Copyright 2014, Christopher Barker, Cris Ewing, . + +

        +
        + Built with Sphinx using a theme provided by Read the Docs. + +
        + +
        +
        + +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file