Skip to content

Commit fc0fa67

Browse files
committed
Merge pull request #1 from kennethreitz/master
Update to match master
2 parents 417afdc + 0f79709 commit fc0fa67

File tree

5 files changed

+255
-2
lines changed

5 files changed

+255
-2
lines changed

docs/contents.rst.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ This part of the guide focuses on best practices for writing Python code.
3232
writing/reading
3333
writing/documentation
3434
writing/tests
35+
writing/logging
3536
writing/gotchas
3637
writing/license
3738

@@ -59,6 +60,7 @@ different scenarios.
5960
scenarios/scientific
6061
scenarios/imaging
6162
scenarios/xml
63+
scenarios/json
6264
scenarios/crypto
6365

6466

docs/scenarios/cli.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ who choose to create a command-line interface because it is quick and simple.
5656
Cliff
5757
------
5858

59-
`Cliff <https://cliff.readthedocs.org/en/latest>`_ is a framework for
59+
`Cliff <http://docs.openstack.org/developer/cliff/>`_ is a framework for
6060
building command-line programs. It uses setuptools entry points to provide
6161
subcommands, output formatters, and other extensions. The framework is meant
6262
to be used to create multi-level commands such as subversion and git, where

docs/scenarios/json.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
JSON
2+
====
3+
4+
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.
5+
6+
Parsing JSON
7+
------------
8+
9+
Take the following string containing JSON data:
10+
11+
.. code-block:: python
12+
13+
json_string = '{"first_name": "Guido", "last_name":"Rossum"}'
14+
15+
It can be parsed like this:
16+
17+
.. code-block:: python
18+
19+
import json
20+
parsed_json = json.loads(json_string)
21+
22+
and can now be used as a normal dictionary:
23+
24+
.. code-block:: python
25+
26+
print(parsed_json['first_name'])
27+
"Guido"
28+
29+
You can also convert a the following to JSON:
30+
31+
.. code-block:: python
32+
33+
d = {
34+
'first_name': 'Guido',
35+
'second_name': 'Rossum',
36+
'titles': ['BDFL', 'Developer'],
37+
}
38+
39+
print(json.dumps(d))
40+
'{"first_name": "Guido", "last_name": "Rossum", "titles": ["BDFL", "Developer"]}'
41+
42+
43+
simplejson
44+
----------
45+
46+
`simplejson <https://simplejson.readthedocs.org/en/latest/>`_ is the externally maintained development version of the json library.
47+
48+
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.

docs/writing/logging.rst

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
Logging
2+
=======
3+
4+
The :mod:`logging` module has been a part of Python's Standard Library since
5+
version 2.3. It is succinctly described in :pep:`282`. The documentation
6+
is notoriously hard to read, except for the `basic logging tutorial`_.
7+
8+
Logging serves two purposes:
9+
10+
- **Diagnostic logging** records events related to the application's
11+
operation. If a user calls in to report an error, for example, the logs
12+
can be searched for context.
13+
- **Audit logging** records events for business analysis. A user's
14+
transactions can be extracted and combined with other user details for
15+
reports or to optimize a business goal.
16+
17+
18+
... or Print?
19+
-------------
20+
21+
The only time that ``print`` is a better option than logging is when
22+
the goal is to display a help statement for a command line application.
23+
Other reasons why logging is better than ``print``:
24+
25+
- The `log record`_, which is created with every logging event, contains
26+
readily available diagnostic information such as the file name,
27+
full path, function, and line number of the logging event.
28+
- Events logged in included modules are automatically accessible via the
29+
root logger
30+
to your application's logging stream, unless you filter them out.
31+
- Logging can be selectively silenced by using the method
32+
:meth:`logging.Logger.setLevel` or disabled by setting the attribute
33+
:attr:`logging.Logger.disabled` to ``True``.
34+
35+
36+
Logging in a Library
37+
--------------------
38+
39+
Notes for `configuring logging for a library`_ are in the
40+
`logging tutorial`_. Because the *user*, not the library, should
41+
dictate what happens when a logging event occurs, one admonition bears
42+
repeating:
43+
44+
.. note::
45+
It is strongly advised that you do not add any handlers other than
46+
NullHandler to your library’s loggers.
47+
48+
49+
Best practice when instantiating loggers in a library is to only create them
50+
using the ``__name__`` global variable: the :mod:`logging` module creates a
51+
hierarchy of loggers using dot notation, so using ``__name__`` ensures
52+
no name collisions.
53+
54+
Here is an example of best practice from the `requests source`_ -- place
55+
this in your ``__init__.py``
56+
57+
.. code-block:: python
58+
59+
# Set default logging handler to avoid "No handler found" warnings.
60+
import logging
61+
try: # Python 2.7+
62+
from logging import NullHandler
63+
except ImportError:
64+
class NullHandler(logging.Handler):
65+
def emit(self, record):
66+
pass
67+
68+
logging.getLogger(__name__).addHandler(NullHandler())
69+
70+
71+
72+
Logging in an Application
73+
-------------------------
74+
75+
The `twelve factor app <http://12factor.net>`_, an authoritative reference
76+
for good practice in application development, contains a section on
77+
`logging best practice <http://12factor.net/logs>`_. It emphatically
78+
advocates for treating log events as an event stream, and for
79+
sending that event stream to standard output to be handled by the
80+
application environment.
81+
82+
83+
There are at least three ways to configure a logger:
84+
85+
- Using an INI-formatted file:
86+
- **Pro**: possible to update configuration while running
87+
using the function :func:`logging.config.listen` to listen
88+
on a socket.
89+
- **Con**: less control (*e.g.* custom subclassed filters or loggers)
90+
than possible when configuring a logger in code.
91+
- Using a dictionary or a JSON-formatted file:
92+
- **Pro**: in addition to updating while running, it is possible to
93+
load from a file using the :mod:`json` module, in the standard
94+
library since Python 2.6.
95+
- **Con**: less control than when configuring a logger in code.
96+
- Using code:
97+
- **Pro**: complete control over the configuration.
98+
- **Con**: modifications require a change to source code.
99+
100+
101+
Example Configuration via an INI File
102+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
103+
104+
Let us say the file is named ``logging_config.ini``.
105+
More details for the file format are in the `logging configuration`_
106+
section of the `logging tutorial`_.
107+
108+
.. code-block:: ini
109+
110+
[loggers]
111+
keys=root
112+
113+
[handlers]
114+
keys=stream_handler
115+
116+
[formatters]
117+
keys=formatter
118+
119+
[logger_root]
120+
level=DEBUG
121+
handlers=stream_handler
122+
123+
[handler_stream_handler]
124+
class=StreamHandler
125+
level=DEBUG
126+
formatter=formatter
127+
args=(sys.stderr,)
128+
129+
[formatter_formatter]
130+
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
131+
132+
133+
Then use :meth:`logging.config.fileConfig` in the code:
134+
135+
.. code-block:: python
136+
137+
import logging
138+
from logging.config import fileConfig
139+
140+
fileConfig('logging_config.ini')
141+
logger = logging.getLogger()
142+
logger.debug('often makes a very good meal of %s', 'visiting tourists')
143+
144+
145+
Example Configuration via a Dictionary
146+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147+
148+
As of Python 2.7, you can use a dictionary with configuration details.
149+
:pep:`319` contains a list of the mandatory and optional elements in
150+
the configuration dictionary.
151+
152+
.. code-block:: python
153+
154+
import logging
155+
from logging.config import dictConfig
156+
157+
logging_config = dict(
158+
version = 1,
159+
formatters = {
160+
'f': {'format':
161+
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s'}
162+
},
163+
handlers = {
164+
'h': {'class': 'logging.StreamHandler',
165+
'formatter': 'f',
166+
'level': logging.DEBUG}
167+
},
168+
loggers = {
169+
root : {'handlers': ['h'],
170+
'level': logging.DEBUG}
171+
}
172+
)
173+
174+
dictConfig(logging_config)
175+
176+
logger = logging.getLogger()
177+
logger.debug('often makes a very good meal of %s', 'visiting tourists')
178+
179+
180+
Example Configuration Directly in Code
181+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182+
183+
.. code-block:: python
184+
185+
import logging
186+
187+
logger = logging.getLogger()
188+
handler = logging.StreamHandler()
189+
formatter = logging.Formatter(
190+
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
191+
handler.setFormatter(formatter)
192+
logger.addHandler(handler)
193+
logger.setLevel(logging.DEBUG)
194+
195+
logger.debug('often makes a very good meal of %s', 'visiting tourists')
196+
197+
198+
.. _basic logging tutorial: http://docs.python.org/howto/logging.html#logging-basic-tutorial
199+
.. _logging configuration: https://docs.python.org/howto/logging.html#configuring-logging
200+
.. _logging tutorial: http://docs.python.org/howto/logging.html
201+
.. _configuring logging for a library: https://docs.python.org/howto/logging.html#configuring-logging-for-a-library
202+
.. _log record: https://docs.python.org/library/logging.html#logrecord-attributes
203+
.. _requests source: https://github.com/kennethreitz/requests

docs/writing/tests.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Some general rules of testing:
5858
good set of tests, you or other maintainers will rely largely on the
5959
testing suite to fix the problem or modify a given behavior. Therefore
6060
the testing code will be read as much as or even more than the running
61-
code. A unit test whose purpose is unclear is not very helpful is this
61+
code. A unit test whose purpose is unclear is not very helpful in this
6262
case.
6363

6464
- Another use of the testing code is as an introduction to new developers. When

0 commit comments

Comments
 (0)