Skip to content

Commit

Permalink
Merge branch 'main' into typewatch
Browse files Browse the repository at this point in the history
* main: (31 commits)
  pythongh-95913: Move subinterpreter exper removal to 3.11 WhatsNew (pythonGH-98345)
  pythongh-95914: Add What's New item describing PEP 670 changes (python#98315)
  Remove unused arrange_output_buffer function from zlibmodule.c. (pythonGH-98358)
  pythongh-98174: Handle EPROTOTYPE under macOS in test_sendfile_fallback_close_peer_in_the_middle_of_receiving (python#98316)
  pythonGH-98327: Reduce scope of catch_warnings() in _make_subprocess_transport (python#98333)
  pythongh-93691: Compiler's code-gen passes location around instead of holding it on the global compiler state (pythonGH-98001)
  pythongh-97669: Create Tools/build/ directory (python#97963)
  pythongh-95534: Improve gzip reading speed by 10% (python#97664)
  pythongh-95913: Forward-port int/str security change to 3.11 What's New in main (python#98344)
  pythonGH-91415: Mention alphabetical sort ordering in the Sorting HOWTO (pythonGH-98336)
  pythongh-97930: Merge with importlib_resources 5.9 (pythonGH-97929)
  pythongh-85525: Remove extra row in doc (python#98337)
  pythongh-85299: Add note warning about entry point guard for asyncio example (python#93457)
  pythongh-97527: IDLE - fix buggy macosx patch (python#98313)
  pythongh-98307: Add docstring and documentation for SysLogHandler.createSocket (pythonGH-98319)
  pythongh-94808: Cover `PyFunction_GetCode`, `PyFunction_GetGlobals`, `PyFunction_GetModule` (python#98158)
  pythonGH-94597: Deprecate child watcher getters and setters (python#98215)
  pythongh-98254: Include stdlib module names in error messages for NameErrors (python#98255)
  Improve speed. Reduce auxiliary memory to 16.6% of the main array. (pythonGH-98294)
  [doc] Update logging cookbook with an example of custom handling of levels. (pythonGH-98290)
  ...
  • Loading branch information
carljm committed Oct 17, 2022
2 parents 2b42bfe + 5fe0431 commit cdbe93b
Show file tree
Hide file tree
Showing 100 changed files with 2,886 additions and 1,338 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Expand Up @@ -55,7 +55,7 @@ Python/traceback.c @iritkatriel
/Lib/html/ @ezio-melotti
/Lib/_markupbase.py @ezio-melotti
/Lib/test/test_html*.py @ezio-melotti
/Tools/scripts/*html5* @ezio-melotti
/Tools/build/parse_html5_entities.py @ezio-melotti

# Import (including importlib).
# Ignoring importlib.h so as to not get flagged on
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/verify-ensurepip-wheels.yml
Expand Up @@ -6,12 +6,12 @@ on:
paths:
- 'Lib/ensurepip/_bundled/**'
- '.github/workflows/verify-ensurepip-wheels.yml'
- 'Tools/scripts/verify_ensurepip_wheels.py'
- 'Tools/build/verify_ensurepip_wheels.py'
pull_request:
paths:
- 'Lib/ensurepip/_bundled/**'
- '.github/workflows/verify-ensurepip-wheels.yml'
- 'Tools/scripts/verify_ensurepip_wheels.py'
- 'Tools/build/verify_ensurepip_wheels.py'

permissions:
contents: read
Expand All @@ -29,4 +29,4 @@ jobs:
with:
python-version: '3'
- name: Compare checksums of bundled pip and setuptools to ones published on PyPI
run: ./Tools/scripts/verify_ensurepip_wheels.py
run: ./Tools/build/verify_ensurepip_wheels.py
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -143,7 +143,7 @@ Tools/ssl/win32
Tools/freeze/test/outdir

# The frozen modules are always generated by the build so we don't
# keep them in the repo. Also see Tools/scripts/freeze_modules.py.
# keep them in the repo. Also see Tools/build/freeze_modules.py.
Python/frozen_modules/*.h
# The manifest can be generated at any time with "make regen-frozen".
Python/frozen_modules/MANIFEST
Expand Down
20 changes: 20 additions & 0 deletions Doc/c-api/refcounting.rst
Expand Up @@ -11,6 +11,26 @@ The macros in this section are used for managing reference counts of Python
objects.


.. c:function:: Py_ssize_t Py_REFCNT(PyObject *o)
Get the reference count of the Python object *o*.
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
.. versionchanged:: 3.11
The parameter type is no longer :c:expr:`const PyObject*`.
.. versionchanged:: 3.10
:c:func:`Py_REFCNT()` is changed to the inline static function.
.. c:function:: void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt)
Set the object *o* reference counter to *refcnt*.
.. versionadded:: 3.9
.. c:function:: void Py_INCREF(PyObject *o)
Increment the reference count for object *o*.
Expand Down
23 changes: 2 additions & 21 deletions Doc/c-api/structures.rst
Expand Up @@ -17,7 +17,8 @@ All Python objects ultimately share a small number of fields at the beginning
of the object's representation in memory. These are represented by the
:c:type:`PyObject` and :c:type:`PyVarObject` types, which are defined, in turn,
by the expansions of some macros also used, whether directly or indirectly, in
the definition of all other Python objects.
the definition of all other Python objects. Additional macros can be found
under :ref:`reference counting <countingrefs>`.


.. c:type:: PyObject
Expand Down Expand Up @@ -121,26 +122,6 @@ the definition of all other Python objects.
.. versionadded:: 3.9
.. c:function:: Py_ssize_t Py_REFCNT(PyObject *o)
Get the reference count of the Python object *o*.
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
.. versionchanged:: 3.11
The parameter type is no longer :c:expr:`const PyObject*`.
.. versionchanged:: 3.10
:c:func:`Py_REFCNT()` is changed to the inline static function.
.. c:function:: void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt)
Set the object *o* reference counter to *refcnt*.
.. versionadded:: 3.9
.. c:function:: Py_ssize_t Py_SIZE(PyVarObject *o)
Get the size of the Python object *o*.
Expand Down
210 changes: 206 additions & 4 deletions Doc/howto/logging-cookbook.rst
Expand Up @@ -276,6 +276,211 @@ choose a different directory name for the log - just ensure that the directory e
and that you have the permissions to create and update files in it.


.. _custom-level-handling:

Custom handling of levels
-------------------------

Sometimes, you might want to do something slightly different from the standard
handling of levels in handlers, where all levels above a threshold get
processed by a handler. To do this, you need to use filters. Let's look at a
scenario where you want to arrange things as follows:

* Send messages of severity ``INFO`` and ``WARNING`` to ``sys.stdout``
* Send messages of severity ``ERROR`` and above to ``sys.stderr``
* Send messages of severity ``DEBUG`` and above to file ``app.log``

Suppose you configure logging with the following JSON:

.. code-block:: json
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"simple": {
"format": "%(levelname)-8s - %(message)s"
}
},
"handlers": {
"stdout": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "simple",
"stream": "ext://sys.stdout",
},
"stderr": {
"class": "logging.StreamHandler",
"level": "ERROR",
"formatter": "simple",
"stream": "ext://sys.stderr"
},
"file": {
"class": "logging.FileHandler",
"formatter": "simple",
"filename": "app.log",
"mode": "w"
}
},
"root": {
"level": "DEBUG",
"handlers": [
"stderr",
"stdout",
"file"
]
}
}
This configuration does *almost* what we want, except that ``sys.stdout`` would
show messages of severity ``ERROR`` and above as well as ``INFO`` and
``WARNING`` messages. To prevent this, we can set up a filter which excludes
those messages and add it to the relevant handler. This can be configured by
adding a ``filters`` section parallel to ``formatters`` and ``handlers``:

.. code-block:: json
"filters": {
"warnings_and_below": {
"()" : "__main__.filter_maker",
"level": "WARNING"
}
}
and changing the section on the ``stdout`` handler to add it:

.. code-block:: json
"stdout": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "simple",
"stream": "ext://sys.stdout",
"filters": ["warnings_and_below"]
}
A filter is just a function, so we can define the ``filter_maker`` (a factory
function) as follows:

.. code-block:: python
def filter_maker(level):
level = getattr(logging, level)
def filter(record):
return record.levelno <= level
return filter
This converts the string argument passed in to a numeric level, and returns a
function which only returns ``True`` if the level of the passed in record is
at or below the specified level. Note that in this example I have defined the
``filter_maker`` in a test script ``main.py`` that I run from the command line,
so its module will be ``__main__`` - hence the ``__main__.filter_maker`` in the
filter configuration. You will need to change that if you define it in a
different module.

With the filter added, we can run ``main.py``, which in full is:

.. code-block:: python
import json
import logging
import logging.config
CONFIG = '''
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"simple": {
"format": "%(levelname)-8s - %(message)s"
}
},
"filters": {
"warnings_and_below": {
"()" : "__main__.filter_maker",
"level": "WARNING"
}
},
"handlers": {
"stdout": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "simple",
"stream": "ext://sys.stdout",
"filters": ["warnings_and_below"]
},
"stderr": {
"class": "logging.StreamHandler",
"level": "ERROR",
"formatter": "simple",
"stream": "ext://sys.stderr"
},
"file": {
"class": "logging.FileHandler",
"formatter": "simple",
"filename": "app.log",
"mode": "w"
}
},
"root": {
"level": "DEBUG",
"handlers": [
"stderr",
"stdout",
"file"
]
}
}
'''
def filter_maker(level):
level = getattr(logging, level)
def filter(record):
return record.levelno <= level
return filter
logging.config.dictConfig(json.loads(CONFIG))
logging.debug('A DEBUG message')
logging.info('An INFO message')
logging.warning('A WARNING message')
logging.error('An ERROR message')
logging.critical('A CRITICAL message')
And after running it like this:

.. code-block:: shell
python main.py 2>stderr.log >stdout.log
We can see the results are as expected:

.. code-block:: shell
$ more *.log
::::::::::::::
app.log
::::::::::::::
DEBUG - A DEBUG message
INFO - An INFO message
WARNING - A WARNING message
ERROR - An ERROR message
CRITICAL - A CRITICAL message
::::::::::::::
stderr.log
::::::::::::::
ERROR - An ERROR message
CRITICAL - A CRITICAL message
::::::::::::::
stdout.log
::::::::::::::
INFO - An INFO message
WARNING - A WARNING message
Configuration server example
----------------------------

Expand Down Expand Up @@ -3503,7 +3708,7 @@ instance). Then, you'd get this kind of result:
WARNING:demo:Bar
>>>
Of course, these above examples show output according to the format used by
Of course, the examples above show output according to the format used by
:func:`~logging.basicConfig`, but you can use a different formatter when you
configure logging.

Expand All @@ -3517,7 +3722,6 @@ need to do or deal with, it is worth mentioning some usage patterns which are
*unhelpful*, and which should therefore be avoided in most cases. The following
sections are in no particular order.


Opening the same log file multiple times
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -3566,7 +3770,6 @@ that in other languages such as Java and C#, loggers are often static class
attributes. However, this pattern doesn't make sense in Python, where the
module (and not the class) is the unit of software decomposition.


Adding handlers other than :class:`NullHandler` to a logger in a library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -3575,7 +3778,6 @@ responsibility of the application developer, not the library developer. If you
are maintaining a library, ensure that you don't add handlers to any of your
loggers other than a :class:`~logging.NullHandler` instance.


Creating a lot of loggers
^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down

0 comments on commit cdbe93b

Please sign in to comment.