From 062cb498e08efa635ea0ee859d1ff1f450b3cd9d Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 18 Jan 2016 10:34:27 -0800 Subject: [PATCH 01/12] fixing errors found on delivery of session 2 lecture --- resources/session01/echo_client.py | 6 +++--- source/presentations/session02.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/session01/echo_client.py b/resources/session01/echo_client.py index 3dad8ab7..6b2f0472 100644 --- a/resources/session01/echo_client.py +++ b/resources/session01/echo_client.py @@ -10,7 +10,7 @@ def client(msg, log_buffer=sys.stderr): print('connecting to {0} port {1}'.format(*server_address), file=log_buffer) # TODO: connect your socket to the server here. - # you can use this as a place to accumulate the entire message echoed back + # you can use this variable to accumulate the entire message received back # from the server received_message = '' @@ -34,8 +34,8 @@ def client(msg, log_buffer=sys.stderr): # the server you will want to close your client socket. print('closing socket', file=log_buffer) - # TODO: when all is said and done, you should return the reply you got - # from the server as the value of this function. + # TODO: when all is said and done, you should return the entire reply + # you received from the server as the return value of this function. if __name__ == '__main__': diff --git a/source/presentations/session02.rst b/source/presentations/session02.rst index 64445658..3dc36eac 100644 --- a/source/presentations/session02.rst +++ b/source/presentations/session02.rst @@ -1334,7 +1334,7 @@ correctly. It should response = response_ok() print('sending response', file=log_buffer) - conn.sendall(response.encode('utf8')) + conn.sendall(response) # ... @@ -1576,7 +1576,7 @@ client what to expect. * baz.html - ``Content-Type: text/html`` There are *many* mime-type identifiers: - http://www.webmaster-toolkit.com/mime-types.shtml + http://www.freeformatter.com/mime-types-list.html Mapping Mime-types From 728d892c53f947f0553c47199d3e4994d26f557d Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 18 Jan 2016 11:17:29 -0800 Subject: [PATCH 02/12] fix make_time script for py3, as pointed out by @iancote --- resources/session02/homework/webroot/make_time.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/resources/session02/homework/webroot/make_time.py b/resources/session02/homework/webroot/make_time.py index d3064dd2..b69acf38 100644 --- a/resources/session02/homework/webroot/make_time.py +++ b/resources/session02/homework/webroot/make_time.py @@ -17,9 +17,6 @@

%s

-"""% time_str - -print html - - +""" % time_str +print(html) From 94b81c64b16d55160dfe6d0411942cd61032800e Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 19 Jan 2016 17:42:20 -0800 Subject: [PATCH 03/12] fix py2 print statements --- source/presentations/session03.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/presentations/session03.rst b/source/presentations/session03.rst index 33c48249..6a2cdbb5 100644 --- a/source/presentations/session03.rst +++ b/source/presentations/session03.rst @@ -149,9 +149,9 @@ We can see this *environment* in Python, too:: .. code-block:: pycon >>> import os - >>> print os.environ['VARIABLE'] + >>> print(os.environ['VARIABLE']) some_value - >>> print os.environ.keys() + >>> print(os.environ.keys()) ['VERSIONER_PYTHON_PREFER_32_BIT', 'VARIABLE', 'LOGNAME', 'USER', 'PATH', ...] @@ -163,7 +163,7 @@ You can alter os environment values while in Python: .. code-block:: pycon >>> os.environ['VARIABLE'] = 'new_value' - >>> print os.environ['VARIABLE'] + >>> print(os.environ['VARIABLE']) new_value .. rst-class:: build From bd2d38515870a171ee97f7247a82b11cf974a9e7 Mon Sep 17 00:00:00 2001 From: cewing Date: Fri, 22 Jan 2016 15:57:16 -0800 Subject: [PATCH 04/12] fix up instructions for constructing a venv --- source/presentations/venv_intro.rst | 43 ++++++++++++++++++----------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/source/presentations/venv_intro.rst b/source/presentations/venv_intro.rst index f60d5119..23665d43 100644 --- a/source/presentations/venv_intro.rst +++ b/source/presentations/venv_intro.rst @@ -20,9 +20,9 @@ Working with Virtual Environments .. rst-class:: large -| For every package +| For every package | installed in the -| system Python, the +| system Python, the | gods kill a kitten .. rst-class:: build @@ -49,36 +49,43 @@ Why Virtual Environments? Creating a Venv --------------- -Since version 3.3, Python has come with a built-in ``venv`` module. This -module provides a command you can use to create virtual environments: -``pyvenv`` +Since version 3.3, Python has come with a built-in ``venv`` module. .. rst-class:: build .. container:: - The basic usage for this command is as follows: + To use the module, you can run it using your Python 3 executable: .. code-block:: bash - - $ pyvenv /path/to/new/environment + + $ python -m venv my_env On Windows you'll need something a bit different: .. code-block:: posh - - c:\Temp>c:\Python35\python -m venv myenv + + c:\Temp>c:\Python35\python -m venv my_env Unless you have the Python executable in your path, in which case this: .. code-block:: posh - - c:\Temp>python -m venv myenv + c:\Temp>python -m venv my_env + + .. note:: Your Python 3 executable may be ``python3``, please substitute + that if required + + Depending on how you installed Python (and on your operating system) you + may also have a ``pyvenv`` command available in your PATH. You can use it like so: + + .. code-block:: bash + + $ pyvenv my_env .. nextslide:: In any of these command forms, the name of the new virtual environment -(``myenv``) is arbitrary. +(``my_env``) is arbitrary. .. rst-class:: build .. container:: @@ -89,13 +96,17 @@ In any of these command forms, the name of the new virtual environment I also suggest that you keep your virtual environments *in the same directory* as the project code you are writing. + Be aware that ``venv`` can be sensitive to path names that contain spaces. + Please make sure that the entire path to your working directory does not + contain any spaces just to be safe. + .. nextslide:: Let's make one for demonstration purposes: .. code-block:: bash - $ pyvenv demoenv + $ python -m venv demoenv $ ls demoenv bin include lib pyvenv.cfg @@ -126,7 +137,7 @@ Every virtual environment you create contains an executable Python command. terminal, you'll see that it is not the one: .. container:: - + .. code-block:: bash $ which python @@ -135,7 +146,7 @@ Every virtual environment you create contains an executable Python command. in powershell: .. code-block:: posh - + $ gcm python ... From 04e76eb625ceae522726594ba41a4359c05abea2 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 26 Jan 2016 11:16:57 -0800 Subject: [PATCH 05/12] fixing flow in session 4 --- source/presentations/session04.rst | 279 +++++++++++++++-------------- 1 file changed, 146 insertions(+), 133 deletions(-) diff --git a/source/presentations/session04.rst b/source/presentations/session04.rst index fc7e52de..e6c67745 100644 --- a/source/presentations/session04.rst +++ b/source/presentations/session04.rst @@ -376,7 +376,7 @@ We'll start by writing a function ``get_inspection_page`` * It will accept keyword arguments for each of the possible query values * It will build a dictionary of request query parameters from incoming - keywords + keywords, using INSPECTION_PARAMS as a template * It will make a request to the inspection service search page using this query * It will return the encoded content and the encoding used as a tuple @@ -713,19 +713,18 @@ print the first of the many divs that match): Parsing Restaurant Data ----------------------- -Now that we have the records we want, we need to parse them. We want to preserve: +Now that we have the records we want, we need to parse them. .. rst-class:: build .. container:: - We'll start by parsing out the information about the restaurant themselves: + We'll start by extracting information about the restaurants: .. rst-class:: build * Name * Address * Location - * ... How is this information contained in our records? @@ -1133,7 +1132,7 @@ interaction over a network" - W3C .. nextslide:: Early Web Services -RSS is one of the earliest forms of Web Services +**RSS** is one of the earliest forms of Web Services .. rst-class:: build .. container:: @@ -1162,10 +1161,11 @@ procedures and pass arguments. * Calls are made via HTTP GET, by passing an XML document * Returns from a call are sent to the client in XML - In python, you can access XML-RPC services using `xmlrpclib`_ from the - standard library + In python, you can access XML-RPC services using `xmlrpc`_ from the + standard library. It has two libraries, ``xmlrpc.client`` and + ``xmlrpc.server`` -.. _xmlrpclib: https://docs.python.org/2/library/xmlrpclib.html +.. _xmlrpc: https://docs.python.org/3.5/library/xmlrpc.html .. nextslide:: SOAP @@ -1189,129 +1189,11 @@ SOAP extends XML-RPC in a couple of useful ways: * The best-known and best-supported module available is **Suds** * The homepage is https://fedorahosted.org/suds/ * It can be installed using ``easy_install`` or ``pip install`` - * But it hasn't been updated since Sept. 2010. - - So we're going to move on - -.. nextslide:: If Not XML, Then What? - -XML is a pretty inefficient medium for transmitting data. There's a lot of -extra characters transmitted that lack any meaning. - -.. rst-class:: build large centered - -**Let's Use JSON** - - -JSON ----- - -JavaScript Object Notation: - -.. rst-class:: build -.. container:: - - .. rst-class:: build - - * a lightweight data-interchange format - * easy for humans to read and write - * easy for machines to parse and generate - - Based on Two Structures: - - * object: ``{ string: value, ...}`` - * array: ``[value, value, ]`` - - .. rst-class:: centered - - pythonic, no? + * A `fork of the library`_ compatible with Python 3 does exist + **I HATE SOAP** -.. nextslide:: JSON Data Types - -JSON provides a few basic data types (see http://json.org/): - -.. rst-class:: build -.. container:: - - .. rst-class:: build - - * string: unicode, anything but ", \\ and control characters - * number: any number, but json does not use octal or hexadecimal - * object, array (we've seen these above) - * true - * false - * null - - .. rst-class:: centered - - **No date type? OMGWTF??!!1!1** - -.. nextslide:: Dates in JSON - -You have two options: - -.. rst-class:: build -.. container:: - - .. container:: - - Option 1 - Unix Epoch Time (number): - - .. code-block:: python - - >>> import time - >>> time.time() - 1358212616.7691269 - - .. container:: - - Option 2 - ISO 8661 (string): - - .. code-block:: python - - >>> import datetime - >>> datetime.datetime.now().isoformat() - '2013-01-14T17:18:10.727240' - - -JSON in Python --------------- - -You can encode python to json, and decode json back to python: - -.. rst-class:: build -.. container:: - - .. code-block:: python - - In [1]: import json - In [2]: array = [1, 2, 3] - In [3]: json.dumps(array) - Out[3]: '[1, 2, 3]' - In [4]: orig = {'foo': [1,2,3], 'bar': 'my resumé', 'baz': True} - In [5]: encoded = json.dumps(orig) - In [6]: encoded - Out[6]: '{"foo": [1, 2, 3], "bar": "my resum\\u00e9", "baz": true}' - In [7]: decoded = json.loads(encoded) - In [8]: decoded == orig - Out[8]: True - - Customizing the encoder or decoder class allows for specialized serializations - - -.. nextslide:: - -the json module also supports reading and writing to *file-like objects* via -``json.dump(fp)`` and ``json.load(fp)`` (note the missing 's') - -.. rst-class:: build -.. container:: - - Remember duck-typing. Anything with a ``.write`` and a ``.read`` method is - *file-like* - - This usage can be much more memory-friendly with large files/sources +.. _fork of the library`: https://github.com/cackharot/suds-py3 .. nextslide:: What about WSDL? @@ -1325,7 +1207,7 @@ interoperability. .. rst-class:: centered - Hardly ever + **Hardly ever** Another reason was to provide extensibility via custom types @@ -1333,16 +1215,37 @@ interoperability. .. rst-class:: centered - Hardly ever + **Hardly ever** + +.. nextslide:: I have to write XML? + +In addition, XML is a pretty inefficient medium for transmitting data. There's +a lot of extra characters transmitted that lack any meaning. + +.. code-block:: xml + + + + + + + + IBM + + + .. nextslide:: Why Do All The Work? -So, if neither of these goals is really achieved by using SOAP, why pay all -the overhead required to use the protocol? +So, if neither of the original goals is really achieved by using SOAP .. rst-class:: build .. container:: + And if the transmission medium is too bloated to use + + why pay all the overhead required to use the protocol? + Is there another way we could consider approaching the problem? .. rst-class:: centered @@ -1434,6 +1337,116 @@ REST is a **Resource Oriented Architecture** * Success: ``HTTP/1.1 204 No Content`` +REST uses JSON +-------------- + +JavaScript Object Notation: + +.. rst-class:: build +.. container:: + + .. rst-class:: build + + * a lightweight data-interchange format + * easy for humans to read and write + * easy for machines to parse and generate + + Based on Two Structures: + + * object: ``{ string: value, ...}`` + * array: ``[value, value, ]`` + + .. rst-class:: centered + + pythonic, no? + + +.. nextslide:: JSON Data Types + +JSON provides a few basic data types (see http://json.org/): + +.. rst-class:: build +.. container:: + + .. rst-class:: build + + * string: unicode, anything but ", \\ and control characters + * number: any number, but json does not use octal or hexadecimal + * object, array (we've seen these above) + * true + * false + * null + + .. rst-class:: centered + + **No date type? OMGWTF??!!1!1** + +.. nextslide:: Dates in JSON + +You have two options: + +.. rst-class:: build +.. container:: + + .. container:: + + Option 1 - Unix Epoch Time (number): + + .. code-block:: python + + >>> import time + >>> time.time() + 1358212616.7691269 + + .. container:: + + Option 2 - ISO 8661 (string): + + .. code-block:: python + + >>> import datetime + >>> datetime.datetime.now().isoformat() + '2013-01-14T17:18:10.727240' + + +JSON in Python +-------------- + +You can encode python to json, and decode json back to python: + +.. rst-class:: build +.. container:: + + .. code-block:: python + + In [1]: import json + In [2]: array = [1, 2, 3] + In [3]: json.dumps(array) + Out[3]: '[1, 2, 3]' + In [4]: orig = {'foo': [1,2,3], 'bar': 'my resumé', 'baz': True} + In [5]: encoded = json.dumps(orig) + In [6]: encoded + Out[6]: '{"foo": [1, 2, 3], "bar": "my resum\\u00e9", "baz": true}' + In [7]: decoded = json.loads(encoded) + In [8]: decoded == orig + Out[8]: True + + Customizing the encoder or decoder class allows for specialized serializations + + +.. nextslide:: + +the json module also supports reading and writing to *file-like objects* via +``json.dump(fp)`` and ``json.load(fp)`` (note the missing 's') + +.. rst-class:: build +.. container:: + + Remember duck-typing. Anything with a ``.write`` and a ``.read`` method is + *file-like* + + This usage can be much more memory-friendly with large files/sources + Playing With REST ----------------- From 322e160f717312bd119f31182f8dc2ab40bd4236 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 26 Jan 2016 11:31:10 -0800 Subject: [PATCH 06/12] fix link error --- source/presentations/session04.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session04.rst b/source/presentations/session04.rst index e6c67745..eed0bf73 100644 --- a/source/presentations/session04.rst +++ b/source/presentations/session04.rst @@ -1193,7 +1193,7 @@ SOAP extends XML-RPC in a couple of useful ways: **I HATE SOAP** -.. _fork of the library`: https://github.com/cackharot/suds-py3 +.. _fork of the library: https://github.com/cackharot/suds-py3 .. nextslide:: What about WSDL? From 2c055c0970ce57203bf20642a6dd501d84ed6eb1 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 2 Feb 2016 16:10:10 -0800 Subject: [PATCH 07/12] we need to install the pyramid bindings for ipython now as well --- source/presentations/session05.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session05.rst b/source/presentations/session05.rst index bdd1b238..156fc99d 100644 --- a/source/presentations/session05.rst +++ b/source/presentations/session05.rst @@ -983,7 +983,7 @@ It's pretty easy to play with your models from in an interpreter. .. code-block:: bash - (ljenv)$ pip install ipython + (ljenv)$ pip install ipython pyramid_ipython Once that finishes, you'll be able to use iPython as your interpreter for this project. From 467342cda01bd936b8562abe75a536197f8e57b3 Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 3 Feb 2016 10:16:56 -0800 Subject: [PATCH 08/12] fix name of intialize_learning_journal_db script so we don't have to type all that crap every time we run it --- source/presentations/session05.rst | 40 ++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/source/presentations/session05.rst b/source/presentations/session05.rst index 156fc99d..4e153be2 100644 --- a/source/presentations/session05.rst +++ b/source/presentations/session05.rst @@ -896,7 +896,7 @@ We have a *model* which allows us to persist Python objects to an SQL database. The ``console_script`` set up as an entry point will help us. -.. nextslide:: ``initialize_learning_journal_db`` +.. nextslide:: Initializing the Database Let's look at that code for a moment. @@ -922,22 +922,48 @@ Let's look at that code for a moment. .. nextslide:: Console Scripts By connecting this function as a ``console script``, our Python package makes -this command available to us. +this command available to us when we install it. .. rst-class:: build .. container:: - When we exectute ``initialize_learning_journal_db`` at the command line, we - will be running this function. + When we exectute the script at the command line, we will be running this + function. - Let's try it out. + But before we try it out, let's update the name we use so we don't have to + type that whole big mess. + + In ``setup.py`` change ``initialize_learning_journal_db`` to ``setup_db``: + + .. code-block:: python + + entry_points="""\ + [paste.app_factory] + main = learning_journal:main + [console_scripts] + setup_db = learning_journal.scripts.initializedb:main + """, + + Then, as you have changed ``setup.py``, re-install your package: + + .. code-block:: bash + + (ljenv)$ python setup.py develop + ... + +.. nextslide:: Running the Script + +Now that the script has been renamed, let's try it out. + +.. rst-class:: build +.. container:: We'll need to provide a configuration file name, let's use ``development.ini``: .. code-block:: bash - (ljenv)$ initialize_learning_journal_db development.ini + (ljenv)$ setup_db development.ini 2015-01-05 18:59:55,426 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 ... 2015-01-05 18:59:55,434 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT @@ -1392,7 +1418,7 @@ messy or incomplete. $ rm learning_journal.sqlite - You can always re-create it by executing ``initialize_learning_journal_db`` + You can always re-create it by executing ``setup_db`` Homework ======== From 46d75b6d0afa00227a53c04b8a9294d22af3e15f Mon Sep 17 00:00:00 2001 From: cewing Date: Wed, 3 Feb 2016 10:17:11 -0800 Subject: [PATCH 09/12] fix missing link target --- source/presentations/session06.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/presentations/session06.rst b/source/presentations/session06.rst index 976003bb..4ee3b920 100644 --- a/source/presentations/session06.rst +++ b/source/presentations/session06.rst @@ -63,6 +63,8 @@ I've added a working ``models.py`` file to our `class repository`_ in the Let's review how it works. +.. _class repository: https://github.com/UWPCE-PythonCert/training.python_web/tree/master/resources/session06 + .. nextslide:: Demo Interaction I've also made a few small changes to make the ``pshell`` command a bit more From 8eea487ae79fe42bcc9d5e85f0ff545f1982e6a6 Mon Sep 17 00:00:00 2001 From: cewing Date: Tue, 16 Feb 2016 15:05:38 -0800 Subject: [PATCH 10/12] fix typo in url, thanks, @gabrielx52 --- source/presentations/session06.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/presentations/session06.rst b/source/presentations/session06.rst index 4ee3b920..652e1af8 100644 --- a/source/presentations/session06.rst +++ b/source/presentations/session06.rst @@ -1437,7 +1437,7 @@ You'll need to update the view configuration to use this new renderer. Starting server in PID 90536. serving on http://0.0.0.0:6543 - * http://localhost:6543/create + * http://localhost:6543/journal/create .. nextslide:: Providing Access From 7637e12bd53b625fbd4bb825aea22d5245939f82 Mon Sep 17 00:00:00 2001 From: cewing Date: Mon, 22 Feb 2016 21:55:23 -0800 Subject: [PATCH 11/12] fixing bad links, thanks everyone who pointed them out. --- source/presentations/session07.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/presentations/session07.rst b/source/presentations/session07.rst index ae290a9e..787bf014 100644 --- a/source/presentations/session07.rst +++ b/source/presentations/session07.rst @@ -162,8 +162,8 @@ In Pyramid these two aspects are handled by separate configuration settings: You can learn about the interfaces for `authentication`_ and `authorization`_ in the Pyramid documentation -.. _authentication: http://docs.pylonsproject.org/docs/pyramid/en/latest/api/interfaces.html#pyramid.interfaces.IAuthenticationPolicy -.. _authorization: http://docs.pylonsproject.org/docs/pyramid/en/latest/api/interfaces.html#pyramid.interfaces.IAuthorizationPolicy +.. _authentication: http://docs.pylonsproject.org/projects/pyramid/en/latest/api/interfaces.html#pyramid.interfaces.IAuthenticationPolicy +.. _authorization: http://docs.pylonsproject.org/projects/pyramid/en/latest/api/interfaces.html#pyramid.interfaces.IAuthorizationPolicy .. nextslide:: Our Journal Security From 858c6f5f500c5165809a062515ef27cfc7d8119e Mon Sep 17 00:00:00 2001 From: cewing Date: Sun, 10 Apr 2016 17:51:42 -0700 Subject: [PATCH 12/12] fix bug in tests --- resources/session02/homework/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/session02/homework/tests.py b/resources/session02/homework/tests.py index aed245e4..45007311 100644 --- a/resources/session02/homework/tests.py +++ b/resources/session02/homework/tests.py @@ -324,7 +324,7 @@ def test_post_request(self): def test_webroot_directory_resources(self): """verify that directory uris are properly served""" message_tmpl = CRLF.join(['GET {0} HTTP/1.1', 'Host: example.com', '']) - root = "webroot" + root = "webroot/" for directory, directories, files in os.walk(root): directory_uri = "/{0}".format(directory[len(root):]) message = message_tmpl.format(directory_uri)