Merge pull request #1 from kennethreitz/master

Update to match master
This commit is contained in:
Matthew Lewis
2015-02-05 13:53:56 -06:00
5 changed files with 255 additions and 2 deletions
+2
View File
@@ -32,6 +32,7 @@ This part of the guide focuses on best practices for writing Python code.
writing/reading
writing/documentation
writing/tests
writing/logging
writing/gotchas
writing/license
@@ -59,6 +60,7 @@ different scenarios.
scenarios/scientific
scenarios/imaging
scenarios/xml
scenarios/json
scenarios/crypto
+1 -1
View File
@@ -56,7 +56,7 @@ who choose to create a command-line interface because it is quick and simple.
Cliff
------
`Cliff <https://cliff.readthedocs.org/en/latest>`_ is a framework for
`Cliff <http://docs.openstack.org/developer/cliff/>`_ is a framework for
building command-line programs. It uses setuptools entry points to provide
subcommands, output formatters, and other extensions. The framework is meant
to be used to create multi-level commands such as subversion and git, where
+48
View File
@@ -0,0 +1,48 @@
JSON
====
The `json <https://docs.python.org/2/library/json.html>`_ library can parse JSON from strings or files. When parsing, the library converts the JSON into a Python dictionary or list. It can also parse Python dictionaries or lists into JSON strings.
Parsing JSON
------------
Take the following string containing JSON data:
.. code-block:: python
json_string = '{"first_name": "Guido", "last_name":"Rossum"}'
It can be parsed like this:
.. code-block:: python
import json
parsed_json = json.loads(json_string)
and can now be used as a normal dictionary:
.. code-block:: python
print(parsed_json['first_name'])
"Guido"
You can also convert a the following to JSON:
.. code-block:: python
d = {
'first_name': 'Guido',
'second_name': 'Rossum',
'titles': ['BDFL', 'Developer'],
}
print(json.dumps(d))
'{"first_name": "Guido", "last_name": "Rossum", "titles": ["BDFL", "Developer"]}'
simplejson
----------
`simplejson <https://simplejson.readthedocs.org/en/latest/>`_ is the externally maintained development version of the json library.
simplejson mimics the json standard library, it is available so that developers that use an older version of python can use the latest features available in the json lib.
+203
View File
@@ -0,0 +1,203 @@
Logging
=======
The :mod:`logging` module has been a part of Python's Standard Library since
version 2.3. It is succinctly described in :pep:`282`. The documentation
is notoriously hard to read, except for the `basic logging tutorial`_.
Logging serves two purposes:
- **Diagnostic logging** records events related to the application's
operation. If a user calls in to report an error, for example, the logs
can be searched for context.
- **Audit logging** records events for business analysis. A user's
transactions can be extracted and combined with other user details for
reports or to optimize a business goal.
... or Print?
-------------
The only time that ``print`` is a better option than logging is when
the goal is to display a help statement for a command line application.
Other reasons why logging is better than ``print``:
- The `log record`_, which is created with every logging event, contains
readily available diagnostic information such as the file name,
full path, function, and line number of the logging event.
- Events logged in included modules are automatically accessible via the
root logger
to your application's logging stream, unless you filter them out.
- Logging can be selectively silenced by using the method
:meth:`logging.Logger.setLevel` or disabled by setting the attribute
:attr:`logging.Logger.disabled` to ``True``.
Logging in a Library
--------------------
Notes for `configuring logging for a library`_ are in the
`logging tutorial`_. Because the *user*, not the library, should
dictate what happens when a logging event occurs, one admonition bears
repeating:
.. note::
It is strongly advised that you do not add any handlers other than
NullHandler to your librarys loggers.
Best practice when instantiating loggers in a library is to only create them
using the ``__name__`` global variable: the :mod:`logging` module creates a
hierarchy of loggers using dot notation, so using ``__name__`` ensures
no name collisions.
Here is an example of best practice from the `requests source`_ -- place
this in your ``__init__.py``
.. code-block:: python
# Set default logging handler to avoid "No handler found" warnings.
import logging
try: # Python 2.7+
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
def emit(self, record):
pass
logging.getLogger(__name__).addHandler(NullHandler())
Logging in an Application
-------------------------
The `twelve factor app <http://12factor.net>`_, an authoritative reference
for good practice in application development, contains a section on
`logging best practice <http://12factor.net/logs>`_. It emphatically
advocates for treating log events as an event stream, and for
sending that event stream to standard output to be handled by the
application environment.
There are at least three ways to configure a logger:
- Using an INI-formatted file:
- **Pro**: possible to update configuration while running
using the function :func:`logging.config.listen` to listen
on a socket.
- **Con**: less control (*e.g.* custom subclassed filters or loggers)
than possible when configuring a logger in code.
- Using a dictionary or a JSON-formatted file:
- **Pro**: in addition to updating while running, it is possible to
load from a file using the :mod:`json` module, in the standard
library since Python 2.6.
- **Con**: less control than when configuring a logger in code.
- Using code:
- **Pro**: complete control over the configuration.
- **Con**: modifications require a change to source code.
Example Configuration via an INI File
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let us say the file is named ``logging_config.ini``.
More details for the file format are in the `logging configuration`_
section of the `logging tutorial`_.
.. code-block:: ini
[loggers]
keys=root
[handlers]
keys=stream_handler
[formatters]
keys=formatter
[logger_root]
level=DEBUG
handlers=stream_handler
[handler_stream_handler]
class=StreamHandler
level=DEBUG
formatter=formatter
args=(sys.stderr,)
[formatter_formatter]
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
Then use :meth:`logging.config.fileConfig` in the code:
.. code-block:: python
import logging
from logging.config import fileConfig
fileConfig('logging_config.ini')
logger = logging.getLogger()
logger.debug('often makes a very good meal of %s', 'visiting tourists')
Example Configuration via a Dictionary
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As of Python 2.7, you can use a dictionary with configuration details.
:pep:`319` contains a list of the mandatory and optional elements in
the configuration dictionary.
.. code-block:: python
import logging
from logging.config import dictConfig
logging_config = dict(
version = 1,
formatters = {
'f': {'format':
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s'}
},
handlers = {
'h': {'class': 'logging.StreamHandler',
'formatter': 'f',
'level': logging.DEBUG}
},
loggers = {
root : {'handlers': ['h'],
'level': logging.DEBUG}
}
)
dictConfig(logging_config)
logger = logging.getLogger()
logger.debug('often makes a very good meal of %s', 'visiting tourists')
Example Configuration Directly in Code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
import logging
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.debug('often makes a very good meal of %s', 'visiting tourists')
.. _basic logging tutorial: http://docs.python.org/howto/logging.html#logging-basic-tutorial
.. _logging configuration: https://docs.python.org/howto/logging.html#configuring-logging
.. _logging tutorial: http://docs.python.org/howto/logging.html
.. _configuring logging for a library: https://docs.python.org/howto/logging.html#configuring-logging-for-a-library
.. _log record: https://docs.python.org/library/logging.html#logrecord-attributes
.. _requests source: https://github.com/kennethreitz/requests
+1 -1
View File
@@ -58,7 +58,7 @@ Some general rules of testing:
good set of tests, you or other maintainers will rely largely on the
testing suite to fix the problem or modify a given behavior. Therefore
the testing code will be read as much as or even more than the running
code. A unit test whose purpose is unclear is not very helpful is this
code. A unit test whose purpose is unclear is not very helpful in this
case.
- Another use of the testing code is as an introduction to new developers. When