From 03ff2dc5a2a1e19743d17c059f5b1c3ea346bae2 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 22 Mar 2013 23:06:21 -0400 Subject: [PATCH 1/9] Fixed casing, added specific version number. --- docs/starting/install/win.rst | 2 +- docs/starting/which-python.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/starting/install/win.rst b/docs/starting/install/win.rst index bcc9445e4..d67b22e53 100644 --- a/docs/starting/install/win.rst +++ b/docs/starting/install/win.rst @@ -4,7 +4,7 @@ Installing Python on Windows ============================ First, download the `latest version `_ -of Python 2 from the official Website. If you want to be sure you are installing a fully +of Python 2.7 from the official Website. If you want to be sure you are installing a fully up-to-date version then use the "Windows Installer" link from the home page of the `Python.org web site `_ . diff --git a/docs/starting/which-python.rst b/docs/starting/which-python.rst index 2486528df..6765a4717 100644 --- a/docs/starting/which-python.rst +++ b/docs/starting/which-python.rst @@ -18,7 +18,7 @@ Which Python to use? Today ----- -If you're choosing a Python interpreter to use, I *highly* recommend you Use +If you're choosing a Python interpreter to use, I *highly* recommend you use Python 2.7.x, unless you have a strong reason not to. From 76217eae5ceabbca3ad2cf651fddf3e7689c04d7 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 22 Mar 2013 23:11:37 -0400 Subject: [PATCH 2/9] Cleaned up the "python-mode" section... This whole section was worded a little funny, so I cleaned it up. Since I haven't used the module mentioned, I can't speak to what should really be here or if this is even a best practice... --- docs/dev/env.rst | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/docs/dev/env.rst b/docs/dev/env.rst index 5c3fd2b47..a4a446a00 100644 --- a/docs/dev/env.rst +++ b/docs/dev/env.rst @@ -64,21 +64,17 @@ to do that which also shows status and warning messages in the statusbar would b Python-mode ^^^^^^^^^^^ -Python-mode_ is complex solution in VIM for work with python code. +Python-mode_ is a complex solution in VIM for working with python code. It has: -- Async python code checking (pylint, pyflakes, pep8, mccabe) in any combination; -- Code refactoring and autocompletion with Rope; -- Fastest python folding; -- Nice and powered python syntax; -- Virtual env support; -- Search by python documentation and run python code; -- More other things like auto pep8 error fixes; -- Very customizable and documented as well; -- Have all required libraries in self; - -And more stuff. +- Async python code checking (pylint, pyflakes, pep8, mccabe) in any combination +- Code refactoring and autocompletion with Rope +- Fast python folding +- Virtualenv support +- Search by python documentation and run python code +- Auto pep8 error fixes +And more. .. _indent: http://www.vim.org/scripts/script.php?script_id=974 .. _syntax: http://www.vim.org/scripts/script.php?script_id=790 From d3a112479ad20f8564d5c6476765ba9e6d1906d0 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 22 Mar 2013 23:23:05 -0400 Subject: [PATCH 3/9] Grammar fixes, whitespace cleanup, flow fixes --- docs/dev/env.rst | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/dev/env.rst b/docs/dev/env.rst index a4a446a00..126a3b7f6 100644 --- a/docs/dev/env.rst +++ b/docs/dev/env.rst @@ -97,8 +97,8 @@ already an Emacs user is `Python Programming in Emacs`_ at EmacsWiki. 1. Emacs itself comes with a python mode. 2. Python ships with an alternate version: `python-mode.el `_ -3. Fabián Ezequiel Gallina's provides nice functionality and - behavior out of the box: `python.el `_ +3. Fabián Ezequiel Gallina's `python.el `_ + provides nice functionality and behavior out of the box .. _Python Programming in Emacs: http://emacswiki.org/emacs/PythonProgrammingInEmacs @@ -141,16 +141,15 @@ The most popular Eclipse plugin for Python development is Aptana's Komodo IDE ---------- `Komodo IDE `_ is developed by -ActiveState and is a commercial IDE for Windows, Mac -and Linux. +ActiveState and is a commercial IDE for Windows, Mac and Linux. Spyder ------ -`Spyder `_ an IDE specifically geared +`Spyder `_ is an IDE specifically geared toward working with scientific python libraries (namely `Scipy `_). -Includes integration with pyflakes_, `pylint `_, +It includes integration with pyflakes_, `pylint `_, and `rope `_. Spyder is open-source (free), offers code completion, syntax highlighting, @@ -160,7 +159,7 @@ class and function browser, and object inspection. WingIDE ------- -`WingIDE `_ a python specific IDE. Runs for Linux, +`WingIDE `_ is a python specific IDE. It runs on Linux, Windows, and Mac (as an X11 application, which frustrates some Mac users). @@ -168,7 +167,7 @@ NINJA-IDE --------- `NINJA-IDE `_ (from the recursive acronym: "Ninja-IDE -Is Not Just Another IDE", is a cross-platform IDE, specially designed to build +Is Not Just Another IDE") is a cross-platform IDE, specially designed to build Python applications, and runs on Linux/X11, Mac OS X and Windows desktop operating systems. Installers for these platforms can be downloaded from the website. @@ -207,7 +206,7 @@ library which you can use to install other packages. The name of the virtual environment (in this case, it was ``venv``) can be anything; omitting the name will place the files in the current directory instead. -In order the start using the virtual environment, run:: +To start using the virtual environment, run:: $ source venv/bin/activate @@ -284,12 +283,12 @@ IDLE `IDLE `_ is an integrated development environment that is part of Python standard library. It is -completely written in Python and uses Tkinter GUI toolkit. Though IDLE -is not suited for full-blown development using Python , it is quite +completely written in Python and uses the Tkinter GUI toolkit. Though IDLE +is not suited for full-blown development using Python, it is quite helpful to try out small Python snippets and experiment with different features in Python. -It provides following features: +It provides the following features: * Python Shell Window (interpreter) * Multi window text editor that colorizes Python code From 696c39fb764fddefa8d8d84755d2760b44d8a5c3 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 22 Mar 2013 23:31:56 -0400 Subject: [PATCH 4/9] s/having a consistent formating/having a consistent format/ --- docs/notes/styleguide.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/notes/styleguide.rst b/docs/notes/styleguide.rst index edaecc1fb..958382c18 100644 --- a/docs/notes/styleguide.rst +++ b/docs/notes/styleguide.rst @@ -4,7 +4,7 @@ The Guide Style Guide ===================== -As with all documentation, having a consistent formating helps make the +As with all documentation, having a consistent format helps make the document more understandable. In order to make The Guide easier to digest, all contributions should fit within the rules of this style guide where appropriate. From 43bad9c176937f255d694fc3ef2c59cf69ab86d6 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 22 Mar 2013 23:35:38 -0400 Subject: [PATCH 5/9] Wrapped text at 78 characters --- Readme.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Readme.rst b/Readme.rst index 48473dc00..a789e7fee 100644 --- a/Readme.rst +++ b/Readme.rst @@ -5,9 +5,13 @@ Hitchhiker's Guide to Python ----------- -**Work in progress. If you'd like to help, please do. There's a lot of work to be done.** +**Work in progress. If you'd like to help, please do. There's a lot of work to +be done.** -This guide is currently under heavy development. This opinionated guide exists to provide both novice and expert Python developers a best-practice handbook to the installation, configuration, and usage of Python on a daily basis. +This guide is currently under heavy development. This opinionated guide +exists to provide both novice and expert Python developers a best-practice +handbook to the installation, configuration, and usage of Python on a daily +basis. Topics include: From c56a94c106e267ac37ea4f0ca91065fbdb646b3f Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 22 Mar 2013 23:47:25 -0400 Subject: [PATCH 6/9] Another dos2unix conversion --- docs/intro/duction.rst | 176 ++++++++++++++++++++--------------------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/docs/intro/duction.rst b/docs/intro/duction.rst index fdebc18d8..7b0cf7dda 100644 --- a/docs/intro/duction.rst +++ b/docs/intro/duction.rst @@ -1,88 +1,88 @@ -Introduction -============ - -From the `official Python website `_: - -Python is a general-purpose, high-level programming language similar -to Tcl, Perl, Ruby, Scheme, or Java. Some of its main key features -include: - -* very clear, readable syntax - - Python's philosophy focuses on readability, from code blocks - delineated with significant whitespace to intuitive keywords in - place of inscrutable punctuation - -* extensive standard libraries and third party modules for virtually - any task - - Python is sometimes described with the words "batteries included" - for its extensive - `standard library `_, which can - includes modules for regular expressions, file IO, fraction handling, - object serialization, and much more. - - Additionally, the - `Python Package Index `_ is available - for users to submit their packages for widespread use, similar to - Perl's `CPAN `_. There is a thriving community - of very powerful Python frameworks and tools like - the `Django `_ web framework and the - `NumPy `_ set of math routines. - -* integration with other systems - - Python can integrate with `Java libraries `_, - enabling it to be used with the rich Java environment that corporate - programmers are used to. It can also be - `extended by C or C++ modules `_ - when speed is of the essence. - -* ubiquity on computers - - Python is available on Windows, \*nix, and Mac. It runs wherever the - Java virtual machine runs, and the reference implementation CPython - can help bring Python to wherever there is a working C compiler. - -* friendly community - - Python has a vibrant and large :ref:`community ` - which maintains wikis, conferences, countless repositories, - mailing lists, IRC channels, and so much more. Heck, the Python - community is even helping to write this guide! - - -.. _about-ref: - -About This Guide ----------------- - -Purpose -~~~~~~~ - -The Hitchhiker's Guide to Python exists to provide both novice and expert -Python developers a best-practice handbook to the installation, configuration, -and usage of Python on a daily basis. - - -By the Community -~~~~~~~~~~~~~~~~ - -This guide is architected and maintained by `Kenneth Reitz -`_ in an open fashion. This is a -community-driven effort that serves one purpose: to serve the community. - -For the Community -~~~~~~~~~~~~~~~~~ - -All contributions to the Guide are welcome, from Pythonistas of all levels. -If you think there's a gap in what the Guide covers, fork the Guide on -GitHub and submit a pull request. Contributions are welcome from everyone, -whether they're an old hand or a first-time Pythonista, and the authors to -the Guide will gladly help if you have any questions about the -appropriateness, completeness, or accuracy of a contribution. - -To get started working on The Hitchhiker's Guide, see -the: doc:`/notes/contribute` page. - - +Introduction +============ + +From the `official Python website `_: + +Python is a general-purpose, high-level programming language similar +to Tcl, Perl, Ruby, Scheme, or Java. Some of its main key features +include: + +* very clear, readable syntax + + Python's philosophy focuses on readability, from code blocks + delineated with significant whitespace to intuitive keywords in + place of inscrutable punctuation + +* extensive standard libraries and third party modules for virtually + any task + + Python is sometimes described with the words "batteries included" + for its extensive + `standard library `_, which includes + modules for regular expressions, file IO, fraction handling, + object serialization, and much more. + + Additionally, the + `Python Package Index `_ is available + for users to submit their packages for widespread use, similar to + Perl's `CPAN `_. There is a thriving community + of very powerful Python frameworks and tools like + the `Django `_ web framework and the + `NumPy `_ set of math routines. + +* integration with other systems + + Python can integrate with `Java libraries `_, + enabling it to be used with the rich Java environment that corporate + programmers are used to. It can also be + `extended by C or C++ modules `_ + when speed is of the essence. + +* ubiquity on computers + + Python is available on Windows, \*nix, and Mac. It runs wherever the + Java virtual machine runs, and the reference implementation CPython + can help bring Python to wherever there is a working C compiler. + +* friendly community + + Python has a vibrant and large :ref:`community ` + which maintains wikis, conferences, countless repositories, + mailing lists, IRC channels, and so much more. Heck, the Python + community is even helping to write this guide! + + +.. _about-ref: + +About This Guide +---------------- + +Purpose +~~~~~~~ + +The Hitchhiker's Guide to Python exists to provide both novice and expert +Python developers a best-practice handbook to the installation, configuration, +and usage of Python on a daily basis. + + +By the Community +~~~~~~~~~~~~~~~~ + +This guide is architected and maintained by `Kenneth Reitz +`_ in an open fashion. This is a +community-driven effort that serves one purpose: to serve the community. + +For the Community +~~~~~~~~~~~~~~~~~ + +All contributions to the Guide are welcome, from Pythonistas of all levels. +If you think there's a gap in what the Guide covers, fork the Guide on +GitHub and submit a pull request. Contributions are welcome from everyone, +whether they're an old hand or a first-time Pythonista, and the authors to +the Guide will gladly help if you have any questions about the +appropriateness, completeness, or accuracy of a contribution. + +To get started working on The Hitchhiker's Guide, see +the: doc:`/notes/contribute` page. + + From 3e603ca9c18991e13af4948b18703fd4dc88e2fc Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 22 Mar 2013 23:49:10 -0400 Subject: [PATCH 7/9] Grammar, US English spelling --- docs/shipping/freezing.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/shipping/freezing.rst b/docs/shipping/freezing.rst index fc46cddff..59f97e8c9 100644 --- a/docs/shipping/freezing.rst +++ b/docs/shipping/freezing.rst @@ -20,19 +20,19 @@ Comparison Solutions and platforms/features supported: =========== ======= ===== ==== ======== ======= ============= ============== ==== ===================== -Solution Windows Linux OS X Python 3 Licence One-file mode Zipfile import Eggs pkg_resources support +Solution Windows Linux OS X Python 3 License One-file mode Zipfile import Eggs pkg_resources support =========== ======= ===== ==== ======== ======= ============= ============== ==== ===================== -bbFreeze yes yes yes no MIT no yes yes yes -py2exe yes no no no MIT yes yes no no -pyInstaller yes yes yes no GPL yes no yes no -cx_Freeze yes yes yes yes PSF no yes yes no +bbFreeze yes yes yes no MIT no yes yes yes +py2exe yes no no no MIT yes yes no no +pyInstaller yes yes yes no GPL yes no yes no +cx_Freeze yes yes yes yes PSF no yes yes no =========== ======= ===== ==== ======== ======= ============= ============== ==== ===================== .. todo:: Add other solutions: py2app .. note:: Freezing Python code on Linux into a Windows executable was only once - supported in PyInstaller, `but later dropped + supported in PyInstaller `and later dropped. `_. .. note:: From 8e9a21e17e84ec7b71fb411594b484e1ac553d5f Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Sat, 23 Mar 2013 00:04:43 -0400 Subject: [PATCH 8/9] Bye bye dos newlines --- docs/writing/reading.rst | 86 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/writing/reading.rst b/docs/writing/reading.rst index 8d1e816d0..e53b30c87 100644 --- a/docs/writing/reading.rst +++ b/docs/writing/reading.rst @@ -1,44 +1,44 @@ -Reading Great Code -================== - -One of the core tenants behind the design of Python is creating -readable code. The motivation behind this design is simple: The number -one thing that Python programmers do is read code. - -One of the secrets of becoming a great Python programmer is to read, -understand, and comprehend excellent code. - -Excellent code typically follows the guidelines outlined in :ref:`code_style`, -and does its best to express a clear and concise intent to the reader. - -Included below is a list of recommended Python projects for reading. Each of -these projects are paragons of excellent Python code. - -- `Howdoi `_ - Howdoi is a code search tool, written in Python. - -- `Flask `_ - Flask is a microframework for Python based on Werkzeug and Jinja2. - It's intended for getting started very quickly and was developed with - best intentions in mind. - -- `Werkzeug `_ - Werkzeug started as simple collection of various utilities for WSGI - applications and has become one of the most advanced WSGI utility modules. - It includes a powerful debugger, full-featured request and response objects, - HTTP utilities to handle entity tags, cache control headers, HTTP dates, - cookie handling, file uploads, a powerful URL routing system and a bunch - of community-contributed addon modules. - -- `Requests `_ - Requests is an Apache2 Licensed HTTP library, written in Python, - for human beings. - -- `Tablib `_ - Tablib is a format-agnostic tabular dataset library, written in Python. - -.. todo:: Embed and explain YouTube video showing python code reading: http://www.youtube.com/watch?v=Jc8M9-LoEuo This may require installing a Sphinx plugin. https://bitbucket.org/birkenfeld/sphinx-contrib/src/a09f29fc16970f34350ca36ac7f229e00b1b1674/youtube?at=default - -.. todo:: Include code examples of exemplary code from each of the projects listed. Explain why it is excellent code. Use complex examples. - +Reading Great Code +================== + +One of the core tenants behind the design of Python is creating +readable code. The motivation behind this design is simple: The number +one thing that Python programmers do is read code. + +One of the secrets of becoming a great Python programmer is to read, +understand, and comprehend excellent code. + +Excellent code typically follows the guidelines outlined in :ref:`code_style`, +and does its best to express a clear and concise intent to the reader. + +Included below is a list of recommended Python projects for reading. Each of +these projects are paragons of excellent Python code. + +- `Howdoi `_ + Howdoi is a code search tool, written in Python. + +- `Flask `_ + Flask is a microframework for Python based on Werkzeug and Jinja2. + It's intended for getting started very quickly and was developed with + best intentions in mind. + +- `Werkzeug `_ + Werkzeug started as simple collection of various utilities for WSGI + applications and has become one of the most advanced WSGI utility modules. + It includes a powerful debugger, full-featured request and response objects, + HTTP utilities to handle entity tags, cache control headers, HTTP dates, + cookie handling, file uploads, a powerful URL routing system and a bunch + of community-contributed addon modules. + +- `Requests `_ + Requests is an Apache2 Licensed HTTP library, written in Python, + for human beings. + +- `Tablib `_ + Tablib is a format-agnostic tabular dataset library, written in Python. + +.. todo:: Embed and explain YouTube video showing python code reading: http://www.youtube.com/watch?v=Jc8M9-LoEuo This may require installing a Sphinx plugin. https://bitbucket.org/birkenfeld/sphinx-contrib/src/a09f29fc16970f34350ca36ac7f229e00b1b1674/youtube?at=default + +.. todo:: Include code examples of exemplary code from each of the projects listed. Explain why it is excellent code. Use complex examples. + .. todo:: Explain techniques to rapidly identify data structures, algorithms and determine what the code is doing. From 7a1077a46428ce758d8ae508d12bde1f29f607c8 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Sat, 23 Mar 2013 00:07:12 -0400 Subject: [PATCH 9/9] dos2unix for writing/structure --- docs/writing/structure.rst | 958 ++++++++++++++++++------------------- 1 file changed, 479 insertions(+), 479 deletions(-) diff --git a/docs/writing/structure.rst b/docs/writing/structure.rst index af388bc79..9f5a1a270 100644 --- a/docs/writing/structure.rst +++ b/docs/writing/structure.rst @@ -1,479 +1,479 @@ -Structuring Your Project -======================== - -By "structure" we mean the decisions you make concerning -how your project best meets its objective. We need to consider how to -best leverage Python's features to create clean, effective code. -In practical terms, "structure" means making clean code whose logic and -dependencies are clear as well as how the files and folders are organized -in the filesystem. - -Which functions should go into which modules? How does data flow through -the project? What features and functions can be grouped together and -isolated? By answering questions like these you can begin to plan, in -a broad sense, what your finished product will look like. - -In this section we take a closer look at Python's module and import -systems as they are the central element to enforcing structure in your -project. We then discuss various perspectives on how to build code which -can be extended and tested reliably. - - -Structure is Key ----------------- - -Thanks to the way imports and modules are handled in Python, it is -relatively easy to structure a Python project. Easy, here, means -that you do not have many constraints and that the module -importing model is easy to grasp. Therefore, you are left with the -pure architectural task of crafting the different parts of your -project and their interactions. - -Easy structuring of a project means it is also easy -to do it poorly. Some signs of a poorly structured project -include: - -- Multiple and messy circular dependencies: if your classes - Table and Chair in furn.py need to import Carpenter from workers.py - to answer a question such as table.isdoneby(), - and if conversely the class Carpenter needs to import Table and Chair, - to answer the question carpenter.whatdo(), then you - have a circular dependency. In this case you will have to resort to - fragile hacks such as using import statements inside - methods or functions. - -- Hidden coupling: each and every change in Table's implementation - breaks 20 tests in unrelated test cases because it breaks Carpenter's code, - which requires very careful surgery to adapt the change. This means - you have too many assumptions about Table in Carpenter's code or the - reverse. - -- Heavy usage of global state or context: instead of explicitly - passing ``(height, width, type, wood)`` to each other, Table - and Carpenter rely on global variables that can be modified - and are modified on the fly by different agents. You need to - scrutinize all access to these global variables to understand why - a rectangular table became a square, and discover that remote - template code is also modifying this context, messing with - table dimensions. - -- Spaghetti code: multiple pages of nested if clauses and for loops - with a lot of copy-pasted procedural code and no - proper segmentation are known as spaghetti code. Python's - meaningful indentation (one of its most controversial features) make - it very hard to maintain this kind of code. So the good news is that - you might not see too much of it. - -- Ravioli code is more likely in Python: it consists of hundreds of - similar little pieces of logic, often classes or objects, without - proper structure. If you never can remember if you have to use - FurnitureTable, AssetTable or Table, or even TableNew for your - task at hand, you might be swimming in ravioli code. - - -Modules -------- - -Python modules are one of the main abstraction layers available and probably the -most natural one. Abstraction layers allow separating code into parts holding -related data and functionality. - -For example, a layer of a project can handle interfacing with user actions, -while another would handle low-level manipulation of data. The most natural way -to separate these two layers is to regroup all interfacing functionality -in one file, and all low-level operations in another file. In this case, -the interface file needs to import the low-level file. This is done with the -`import` and `from ... import` statements. - -As soon as you use `import` statements you use modules. These can be either built-in -modules such as `os` and `sys`, third-party modules you have installed in your -environment, or your project's internal modules. - -To keep in line with the style guide, keep module names short, lowercase, and -be sure to avoid using special symbols like the dot (.) or question mark (?). -So a file name like `my.spam.py` is one you should avoid! Naming this way -will interfere with the way python looks for modules. - -In this example python expects to find a "spam.py" file in a folder named "my" -which is not the case. There is an -`example `_ of how the -dot notation should be used in the python docs. - -If you'd like you could name it as `my_spam.py` but even our friend the -underscore should not be seen often in module names. - -Aside for some naming restrictions, nothing special is required for a Python file -to be a module, but the import mechanism needs to be understood in order to use -this concept properly and avoid some issues. - -Concretely, the `import modu` statement will look for the proper file, which is -`modu.py` in the same directory as the caller if it exists. If it is not -found, the Python interpreter will search for `modu.py` in the "path" -recursively and raise an ImportError exception if it is not found. - -Once `modu.py` is found, the Python interpreter will execute the module in an -isolated scope. Any top-level statement in `modu.py` will be executed, -including other imports if any. Function and class definitions are stored in -the module's dictionary. - -Then, the module's variables, functions, and classes will be available to the caller -through the module's namespace, a central concept in programming that is -particularly helpful and powerful in Python. - -In many languages, an `include file` directive is used by the preprocessor to -take all code found in the file and 'copy' it into the caller's code. It is -different in Python: the included code is isolated in a module namespace, which -means that you generally don't have to worry that the included code could have -unwanted effects, e.g. override an existing function with the same name. - -It is possible to simulate the more standard behavior by using a special syntax -of the import statement: `from modu import *`. This is generally considered bad -practice. **Using `import *` makes code harder to read and makes dependencies less -compartmentalized**. - -Using `from modu import func` is a way to pinpoint the function you want to -import and put it in the global namespace. While much less harmful than `import -*` because it shows explicitly what is imported in the global namespace, its -advantage over a simpler `import modu` is only that it will save some typing. - -**Very bad** - -.. code-block:: python - - [...] - from modu import * - [...] - x = sqrt(4) # Is sqrt part of modu? A builtin? Defined above? - -**Better** - -.. code-block:: python - - from modu import sqrt - [...] - x = sqrt(4) # sqrt may be part of modu, if not redefined in between - -**Best** - -.. code-block:: python - - import modu - [...] - x = modu.sqrt(4) # sqrt is visibly part of modu's namespace - -As said in the section about style, readability is one of the main features of -Python. Readability means to avoid useless boilerplate text and clutter, -therefore some efforts are spent trying to achieve a certain level of brevity. -But terseness and obscurity are the limits where brevity should stop. Being -able to tell immediately where a class or function comes from, as in the -`modu.func` idiom, greatly improves code readability and understandability in -all but the simplest single file projects. - - -Packages --------- - -Python provides a very straightforward packaging system, which is simply an -extension of the module mechanism to a directory. - -Any directory with an __init__.py file is considered a Python package. The -different modules in the package are imported in a similar manner as plain -modules, but with a special behavior for the __init__.py file, which is used to -gather all package-wide definitions. - -A file modu.py in the directory pack/ is imported with the statement `import -pack.modu`. This statement will look for an __init__.py file in `pack`, execute -all of its top-level statements. Then it will look for a file `pack/modu.py` and -execute all of its top-level statements. After these operations, any variable, -function, or class defined in modu.py is available in the pack.modu namespace. - -A commonly seen issue is to add too much code to __init__.py -files. When the project complexity grows, there may be sub-packages and -sub-sub-packages in a deep directory structure, and then, importing a single item -from a sub-sub-package will require executing all __init__.py files met while -traversing the tree. - -Leaving an __init__.py file empty is considered normal and even a good practice, -if the package's modules and sub-packages do not need to share any code. - -Lastly, a convenient syntax is available for importing deeply nested packages: -`import very.deep.module as mod`. This allows you to use `mod` in place of the verbose -repetition of `very.deep.module`. - -Object-oriented programming ---------------------------- - -Python is sometimes described as an object-oriented programming language. This -can be somewhat misleading and needs to be clarified. - -In Python, everything is an object, and can be handled as such. This is what is -meant when we say that, for example, functions are first-class objects. -Functions, classes, strings, and even types are objects in Python: like any -objects, they have a type, they can be passed as function arguments, they may -have methods and properties. In this understanding, Python is an -object-oriented language. - -However, unlike Java, Python does not impose object-oriented programming as the -main programming paradigm. It is perfectly viable for a Python project to not -be object-oriented, i.e. to use no or very few class definitions, class -inheritance, or any other mechanisms that are specific to object-oriented -programming. - -Moreover, as seen in the modules_ section, the way Python handles modules and -namespaces gives the developer a natural way to ensure the -encapsulation and separation of abstraction layers, both being the most common -reasons to use object-orientation. Therefore, Python programmers have more -latitude to not use object-orientation, when it is not required by the business -model. - -There are some reasons to avoid unnecessary object-orientation. Defining -custom classes is useful when we want to glue together some state and some -functionality. The problem, as pointed out by the discussions about functional -programming, comes from the "state" part of the equation. - -In some architectures, typically web applications, multiple instances of Python -processes are spawned to respond to external requests that can -happen at the same time. In this case, holding some state into instantiated -objects, which means keeping some static information about the world, is prone -to concurrency problems or race-conditions. Sometimes, between the initialization of -the state of an object (usually done with the __init__() method) and the actual use -of the object state through one of its methods, the world may have changed, and -the retained state may be outdated. For example, a request may load an item in -memory and mark it as read by a user. If another request requires the deletion -of this item at the same, it may happen that the deletion actually occurs after -the first process loaded the item, and then we have to mark as read a deleted -object. - -This and other issues led to the idea that using stateless functions is a -better programming paradigm. - -Another way to say the same thing is to suggest using functions and procedures -with as few implicit contexts and side-effects as possible. A function's -implicit context is made up of any of the global variables or items in the persistence layer -that are accessed from within the function. Side-effects are the changes that a function makes -to its implicit context. If a function saves or deletes data in a global variable or -in the persistence layer, it is said to have a side-effect. - -Carefully isolating functions with context and side-effects from functions with -logic (called pure functions) allow the following benefits: - -- Pure functions are deterministic: given a fixed input, - the output will always be the same. - -- Pure functions are much easier to change or replace if they need to - be refactored or optimized. - -- Pure functions are easier to test with unit-tests: There is less - need for complex context setup and data cleaning afterwards. - -- Pure functions are easier to manipulate, decorate, and pass-around. - -In summary, pure functions, without any context or side-effects, are more -efficient building blocks than classes and objects for some architectures. - -Obviously, object-orientation is useful and even necessary in many cases, for -example when developing graphical desktop applications or games, where the -things that are manipulated (windows, buttons, avatars, vehicles) have a -relatively long life of their own in the computer's memory. - - -Decorators ----------- - -The Python language provides a simple yet powerful syntax called 'decorators'. -A decorator is a function or a class that wraps (or decorates) a function -or a method. The 'decorated' function or method will replace the original -'undecorated' function or method. Because functions are first-class objects -in Python, it can be done 'manually', but using the @decorator syntax is -clearer and thus preferred. - -.. code-block:: python - - def foo(): - # do something - - def decorator(func): - # manipulate func - return func - - foo = decorator(foo) # Manually decorate - - @decorator - def bar(): - # Do something - # bar() is decorated - -This mechanism is useful for separating concerns and avoiding -external un-related logic 'polluting' the core logic of the function -or method. A good example of a piece of functionality that is better handled -with decoration is memoization or caching: you want to store the results of an -expensive function in a table and use them directly instead of recomputing -them when they have already been computed. This is clearly not part -of the function logic. - -Dynamic typing --------------- - -Python is said to be dynamically typed, which means that variables -do not have a fixed type. In fact, in Python, variables are very -different from what they are in many other languages, specifically -strongly-typed languages. Variables are not a segment of the computer's -memory where some value is written, they are 'tags' or 'names' pointing -to objects. It is therefore possible for the variable 'a' to be set to -the value 1, then to the value 'a string', then to a function. - -The dynamic typing of Python is often considered to be a weakness, and indeed -it can lead to complexities and hard-to-debug code. Something -named 'a' can be set to many different things, and the developer or the -maintainer needs to track this name in the code to make sure it has not -been set to a completely unrelated object. - -Some guidelines help to avoid this issue: - -- Avoid using the same variable name for different things. - -**Bad** - -.. code-block:: python - - a = 1 - a = 'a string' - def a(): - pass # Do something - -**Good** - -.. code-block:: python - - count = 1 - msg = 'a string' - def func(): - pass # Do something - -Using short functions or methods helps reduce the risk -of using the same name for two unrelated things. - -It is better to use different names even for things that are related, -when they have a different type: - -**Bad** - -.. code-block:: python - - items = 'a b c d' # This is a string... - items = items.split(' ') # ...becoming a list - items = set(items) # ...and then a set - -There is no efficiency gain when reusing names: the assignments -will have to create new objects anyway. However, when the complexity -grows and each assignment is separated by other lines of code, including -'if' branches and loops, it becomes harder to ascertain what a given -variable's type is. - -Some coding practices, like functional programming, recommend never reassigning a variable. -In Java this is done with the `final` keyword. Python does not have a `final` keyword -and it would be against its philosophy anyway. However, it may be a good -discipline to avoid assigning to a variable more than once, and it helps -in grasping the concept of mutable and immutable types. - -Mutable and immutable types ---------------------------- - -Python has two kinds of built-in or user-defined types. - -Mutable types are those that allow in-place modification -of the content. Typical mutables are lists and dictionaries: -All lists have mutating methods, like append() or pop(), and -can be modified in place. The same goes for dictionaries. - -Immutable types provide no method for changing their content. -For instance, the variable x set to the integer 6 has no "increment" method. If you -want to compute x + 1, you have to create another integer and give it -a name. - -.. code-block:: python - - my_list = [1, 2, 3] - my_list[0] = 4 - print my_list # [4, 2, 3] <- The same list as changed - - x = 6 - x = x + 1 # The new x is another object - -One consequence of this difference in behavior is that mutable -types are not "stable", and therefore cannot be used as dictionary -keys. - -Using properly mutable types for things that are mutable in nature -and immutable types for things that are fixed in nature -helps to clarify the intent of the code. - -For example, the immutable equivalent of a list is the tuple, created -with ``(1, 2)``. This tuple is a pair that cannot be changed in-place, -and can be used as a key for a dictionary. - -One peculiarity of Python that can surprise beginners is that -strings are immutable. This means that when constructing a string from -its parts, it is much more efficient to accumulate the parts in a list, -which is mutable, and then glue ('join') the parts together when the -full string is needed. One thing to notice, however, is that list -comprehensions are better and faster than constructing a list in a loop -with calls to append(). - -**Bad** - -.. code-block:: python - - # create a concatenated string from 0 to 19 (e.g. "012..1819") - nums = "" - for n in range(20): - nums += str(n) # slow and inefficient - print nums - -**Good** - -.. code-block:: python - - # create a concatenated string from 0 to 19 (e.g. "012..1819") - nums = [] - for n in range(20): - nums.append(str(n)) - print "".join(nums) # much more efficient - -**Best** - -.. code-block:: python - - # create a concatenated string from 0 to 19 (e.g. "012..1819") - nums = [str(n) for n in range(20)] - print "".join(nums) - -One final thing to mention about strings is that using join() is not always -best. In the instances where you are creating a new string from a pre-determined -number of strings, using the addition operator is actually faster, but in cases -like above or in cases where you are adding to an existing string, using join() -should be your preferred method. - -.. code-block:: python - - foo = 'foo' - bar = 'bar' - - foobar = foo + bar # This is good - foo += 'ooo' # This is bad, instead you should do: - foo = ''.join([foo, 'ooo']) - -Vendorizing Dependencies ------------------------- - - - -Runners -------- - - -Further Reading ---------------- - -- http://docs.python.org/2/library/ -- http://www.diveintopython.net/toc/index.html +Structuring Your Project +======================== + +By "structure" we mean the decisions you make concerning +how your project best meets its objective. We need to consider how to +best leverage Python's features to create clean, effective code. +In practical terms, "structure" means making clean code whose logic and +dependencies are clear as well as how the files and folders are organized +in the filesystem. + +Which functions should go into which modules? How does data flow through +the project? What features and functions can be grouped together and +isolated? By answering questions like these you can begin to plan, in +a broad sense, what your finished product will look like. + +In this section we take a closer look at Python's module and import +systems as they are the central element to enforcing structure in your +project. We then discuss various perspectives on how to build code which +can be extended and tested reliably. + + +Structure is Key +---------------- + +Thanks to the way imports and modules are handled in Python, it is +relatively easy to structure a Python project. Easy, here, means +that you do not have many constraints and that the module +importing model is easy to grasp. Therefore, you are left with the +pure architectural task of crafting the different parts of your +project and their interactions. + +Easy structuring of a project means it is also easy +to do it poorly. Some signs of a poorly structured project +include: + +- Multiple and messy circular dependencies: if your classes + Table and Chair in furn.py need to import Carpenter from workers.py + to answer a question such as table.isdoneby(), + and if conversely the class Carpenter needs to import Table and Chair, + to answer the question carpenter.whatdo(), then you + have a circular dependency. In this case you will have to resort to + fragile hacks such as using import statements inside + methods or functions. + +- Hidden coupling: each and every change in Table's implementation + breaks 20 tests in unrelated test cases because it breaks Carpenter's code, + which requires very careful surgery to adapt the change. This means + you have too many assumptions about Table in Carpenter's code or the + reverse. + +- Heavy usage of global state or context: instead of explicitly + passing ``(height, width, type, wood)`` to each other, Table + and Carpenter rely on global variables that can be modified + and are modified on the fly by different agents. You need to + scrutinize all access to these global variables to understand why + a rectangular table became a square, and discover that remote + template code is also modifying this context, messing with + table dimensions. + +- Spaghetti code: multiple pages of nested if clauses and for loops + with a lot of copy-pasted procedural code and no + proper segmentation are known as spaghetti code. Python's + meaningful indentation (one of its most controversial features) make + it very hard to maintain this kind of code. So the good news is that + you might not see too much of it. + +- Ravioli code is more likely in Python: it consists of hundreds of + similar little pieces of logic, often classes or objects, without + proper structure. If you never can remember if you have to use + FurnitureTable, AssetTable or Table, or even TableNew for your + task at hand, you might be swimming in ravioli code. + + +Modules +------- + +Python modules are one of the main abstraction layers available and probably the +most natural one. Abstraction layers allow separating code into parts holding +related data and functionality. + +For example, a layer of a project can handle interfacing with user actions, +while another would handle low-level manipulation of data. The most natural way +to separate these two layers is to regroup all interfacing functionality +in one file, and all low-level operations in another file. In this case, +the interface file needs to import the low-level file. This is done with the +`import` and `from ... import` statements. + +As soon as you use `import` statements you use modules. These can be either built-in +modules such as `os` and `sys`, third-party modules you have installed in your +environment, or your project's internal modules. + +To keep in line with the style guide, keep module names short, lowercase, and +be sure to avoid using special symbols like the dot (.) or question mark (?). +So a file name like `my.spam.py` is one you should avoid! Naming this way +will interfere with the way python looks for modules. + +In this example python expects to find a "spam.py" file in a folder named "my" +which is not the case. There is an +`example `_ of how the +dot notation should be used in the python docs. + +If you'd like you could name it as `my_spam.py` but even our friend the +underscore should not be seen often in module names. + +Aside for some naming restrictions, nothing special is required for a Python file +to be a module, but the import mechanism needs to be understood in order to use +this concept properly and avoid some issues. + +Concretely, the `import modu` statement will look for the proper file, which is +`modu.py` in the same directory as the caller if it exists. If it is not +found, the Python interpreter will search for `modu.py` in the "path" +recursively and raise an ImportError exception if it is not found. + +Once `modu.py` is found, the Python interpreter will execute the module in an +isolated scope. Any top-level statement in `modu.py` will be executed, +including other imports if any. Function and class definitions are stored in +the module's dictionary. + +Then, the module's variables, functions, and classes will be available to the caller +through the module's namespace, a central concept in programming that is +particularly helpful and powerful in Python. + +In many languages, an `include file` directive is used by the preprocessor to +take all code found in the file and 'copy' it into the caller's code. It is +different in Python: the included code is isolated in a module namespace, which +means that you generally don't have to worry that the included code could have +unwanted effects, e.g. override an existing function with the same name. + +It is possible to simulate the more standard behavior by using a special syntax +of the import statement: `from modu import *`. This is generally considered bad +practice. **Using `import *` makes code harder to read and makes dependencies less +compartmentalized**. + +Using `from modu import func` is a way to pinpoint the function you want to +import and put it in the global namespace. While much less harmful than `import +*` because it shows explicitly what is imported in the global namespace, its +advantage over a simpler `import modu` is only that it will save some typing. + +**Very bad** + +.. code-block:: python + + [...] + from modu import * + [...] + x = sqrt(4) # Is sqrt part of modu? A builtin? Defined above? + +**Better** + +.. code-block:: python + + from modu import sqrt + [...] + x = sqrt(4) # sqrt may be part of modu, if not redefined in between + +**Best** + +.. code-block:: python + + import modu + [...] + x = modu.sqrt(4) # sqrt is visibly part of modu's namespace + +As said in the section about style, readability is one of the main features of +Python. Readability means to avoid useless boilerplate text and clutter, +therefore some efforts are spent trying to achieve a certain level of brevity. +But terseness and obscurity are the limits where brevity should stop. Being +able to tell immediately where a class or function comes from, as in the +`modu.func` idiom, greatly improves code readability and understandability in +all but the simplest single file projects. + + +Packages +-------- + +Python provides a very straightforward packaging system, which is simply an +extension of the module mechanism to a directory. + +Any directory with an __init__.py file is considered a Python package. The +different modules in the package are imported in a similar manner as plain +modules, but with a special behavior for the __init__.py file, which is used to +gather all package-wide definitions. + +A file modu.py in the directory pack/ is imported with the statement `import +pack.modu`. This statement will look for an __init__.py file in `pack`, execute +all of its top-level statements. Then it will look for a file `pack/modu.py` and +execute all of its top-level statements. After these operations, any variable, +function, or class defined in modu.py is available in the pack.modu namespace. + +A commonly seen issue is to add too much code to __init__.py +files. When the project complexity grows, there may be sub-packages and +sub-sub-packages in a deep directory structure, and then, importing a single item +from a sub-sub-package will require executing all __init__.py files met while +traversing the tree. + +Leaving an __init__.py file empty is considered normal and even a good practice, +if the package's modules and sub-packages do not need to share any code. + +Lastly, a convenient syntax is available for importing deeply nested packages: +`import very.deep.module as mod`. This allows you to use `mod` in place of the verbose +repetition of `very.deep.module`. + +Object-oriented programming +--------------------------- + +Python is sometimes described as an object-oriented programming language. This +can be somewhat misleading and needs to be clarified. + +In Python, everything is an object, and can be handled as such. This is what is +meant when we say that, for example, functions are first-class objects. +Functions, classes, strings, and even types are objects in Python: like any +objects, they have a type, they can be passed as function arguments, they may +have methods and properties. In this understanding, Python is an +object-oriented language. + +However, unlike Java, Python does not impose object-oriented programming as the +main programming paradigm. It is perfectly viable for a Python project to not +be object-oriented, i.e. to use no or very few class definitions, class +inheritance, or any other mechanisms that are specific to object-oriented +programming. + +Moreover, as seen in the modules_ section, the way Python handles modules and +namespaces gives the developer a natural way to ensure the +encapsulation and separation of abstraction layers, both being the most common +reasons to use object-orientation. Therefore, Python programmers have more +latitude to not use object-orientation, when it is not required by the business +model. + +There are some reasons to avoid unnecessary object-orientation. Defining +custom classes is useful when we want to glue together some state and some +functionality. The problem, as pointed out by the discussions about functional +programming, comes from the "state" part of the equation. + +In some architectures, typically web applications, multiple instances of Python +processes are spawned to respond to external requests that can +happen at the same time. In this case, holding some state into instantiated +objects, which means keeping some static information about the world, is prone +to concurrency problems or race-conditions. Sometimes, between the initialization of +the state of an object (usually done with the __init__() method) and the actual use +of the object state through one of its methods, the world may have changed, and +the retained state may be outdated. For example, a request may load an item in +memory and mark it as read by a user. If another request requires the deletion +of this item at the same, it may happen that the deletion actually occurs after +the first process loaded the item, and then we have to mark as read a deleted +object. + +This and other issues led to the idea that using stateless functions is a +better programming paradigm. + +Another way to say the same thing is to suggest using functions and procedures +with as few implicit contexts and side-effects as possible. A function's +implicit context is made up of any of the global variables or items in the persistence layer +that are accessed from within the function. Side-effects are the changes that a function makes +to its implicit context. If a function saves or deletes data in a global variable or +in the persistence layer, it is said to have a side-effect. + +Carefully isolating functions with context and side-effects from functions with +logic (called pure functions) allow the following benefits: + +- Pure functions are deterministic: given a fixed input, + the output will always be the same. + +- Pure functions are much easier to change or replace if they need to + be refactored or optimized. + +- Pure functions are easier to test with unit-tests: There is less + need for complex context setup and data cleaning afterwards. + +- Pure functions are easier to manipulate, decorate, and pass-around. + +In summary, pure functions, without any context or side-effects, are more +efficient building blocks than classes and objects for some architectures. + +Obviously, object-orientation is useful and even necessary in many cases, for +example when developing graphical desktop applications or games, where the +things that are manipulated (windows, buttons, avatars, vehicles) have a +relatively long life of their own in the computer's memory. + + +Decorators +---------- + +The Python language provides a simple yet powerful syntax called 'decorators'. +A decorator is a function or a class that wraps (or decorates) a function +or a method. The 'decorated' function or method will replace the original +'undecorated' function or method. Because functions are first-class objects +in Python, it can be done 'manually', but using the @decorator syntax is +clearer and thus preferred. + +.. code-block:: python + + def foo(): + # do something + + def decorator(func): + # manipulate func + return func + + foo = decorator(foo) # Manually decorate + + @decorator + def bar(): + # Do something + # bar() is decorated + +This mechanism is useful for separating concerns and avoiding +external un-related logic 'polluting' the core logic of the function +or method. A good example of a piece of functionality that is better handled +with decoration is memoization or caching: you want to store the results of an +expensive function in a table and use them directly instead of recomputing +them when they have already been computed. This is clearly not part +of the function logic. + +Dynamic typing +-------------- + +Python is said to be dynamically typed, which means that variables +do not have a fixed type. In fact, in Python, variables are very +different from what they are in many other languages, specifically +strongly-typed languages. Variables are not a segment of the computer's +memory where some value is written, they are 'tags' or 'names' pointing +to objects. It is therefore possible for the variable 'a' to be set to +the value 1, then to the value 'a string', then to a function. + +The dynamic typing of Python is often considered to be a weakness, and indeed +it can lead to complexities and hard-to-debug code. Something +named 'a' can be set to many different things, and the developer or the +maintainer needs to track this name in the code to make sure it has not +been set to a completely unrelated object. + +Some guidelines help to avoid this issue: + +- Avoid using the same variable name for different things. + +**Bad** + +.. code-block:: python + + a = 1 + a = 'a string' + def a(): + pass # Do something + +**Good** + +.. code-block:: python + + count = 1 + msg = 'a string' + def func(): + pass # Do something + +Using short functions or methods helps reduce the risk +of using the same name for two unrelated things. + +It is better to use different names even for things that are related, +when they have a different type: + +**Bad** + +.. code-block:: python + + items = 'a b c d' # This is a string... + items = items.split(' ') # ...becoming a list + items = set(items) # ...and then a set + +There is no efficiency gain when reusing names: the assignments +will have to create new objects anyway. However, when the complexity +grows and each assignment is separated by other lines of code, including +'if' branches and loops, it becomes harder to ascertain what a given +variable's type is. + +Some coding practices, like functional programming, recommend never reassigning a variable. +In Java this is done with the `final` keyword. Python does not have a `final` keyword +and it would be against its philosophy anyway. However, it may be a good +discipline to avoid assigning to a variable more than once, and it helps +in grasping the concept of mutable and immutable types. + +Mutable and immutable types +--------------------------- + +Python has two kinds of built-in or user-defined types. + +Mutable types are those that allow in-place modification +of the content. Typical mutables are lists and dictionaries: +All lists have mutating methods, like append() or pop(), and +can be modified in place. The same goes for dictionaries. + +Immutable types provide no method for changing their content. +For instance, the variable x set to the integer 6 has no "increment" method. If you +want to compute x + 1, you have to create another integer and give it +a name. + +.. code-block:: python + + my_list = [1, 2, 3] + my_list[0] = 4 + print my_list # [4, 2, 3] <- The same list as changed + + x = 6 + x = x + 1 # The new x is another object + +One consequence of this difference in behavior is that mutable +types are not "stable", and therefore cannot be used as dictionary +keys. + +Using properly mutable types for things that are mutable in nature +and immutable types for things that are fixed in nature +helps to clarify the intent of the code. + +For example, the immutable equivalent of a list is the tuple, created +with ``(1, 2)``. This tuple is a pair that cannot be changed in-place, +and can be used as a key for a dictionary. + +One peculiarity of Python that can surprise beginners is that +strings are immutable. This means that when constructing a string from +its parts, it is much more efficient to accumulate the parts in a list, +which is mutable, and then glue ('join') the parts together when the +full string is needed. One thing to notice, however, is that list +comprehensions are better and faster than constructing a list in a loop +with calls to append(). + +**Bad** + +.. code-block:: python + + # create a concatenated string from 0 to 19 (e.g. "012..1819") + nums = "" + for n in range(20): + nums += str(n) # slow and inefficient + print nums + +**Good** + +.. code-block:: python + + # create a concatenated string from 0 to 19 (e.g. "012..1819") + nums = [] + for n in range(20): + nums.append(str(n)) + print "".join(nums) # much more efficient + +**Best** + +.. code-block:: python + + # create a concatenated string from 0 to 19 (e.g. "012..1819") + nums = [str(n) for n in range(20)] + print "".join(nums) + +One final thing to mention about strings is that using join() is not always +best. In the instances where you are creating a new string from a pre-determined +number of strings, using the addition operator is actually faster, but in cases +like above or in cases where you are adding to an existing string, using join() +should be your preferred method. + +.. code-block:: python + + foo = 'foo' + bar = 'bar' + + foobar = foo + bar # This is good + foo += 'ooo' # This is bad, instead you should do: + foo = ''.join([foo, 'ooo']) + +Vendorizing Dependencies +------------------------ + + + +Runners +------- + + +Further Reading +--------------- + +- http://docs.python.org/2/library/ +- http://www.diveintopython.net/toc/index.html