Skip to content

Commit cdbe93b

Browse files
committed
Merge branch 'main' into typewatch
* 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) ...
2 parents 2b42bfe + 5fe0431 commit cdbe93b

File tree

100 files changed

+2886
-1338
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+2886
-1338
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Python/traceback.c @iritkatriel
5555
/Lib/html/ @ezio-melotti
5656
/Lib/_markupbase.py @ezio-melotti
5757
/Lib/test/test_html*.py @ezio-melotti
58-
/Tools/scripts/*html5* @ezio-melotti
58+
/Tools/build/parse_html5_entities.py @ezio-melotti
5959

6060
# Import (including importlib).
6161
# Ignoring importlib.h so as to not get flagged on

.github/workflows/verify-ensurepip-wheels.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ on:
66
paths:
77
- 'Lib/ensurepip/_bundled/**'
88
- '.github/workflows/verify-ensurepip-wheels.yml'
9-
- 'Tools/scripts/verify_ensurepip_wheels.py'
9+
- 'Tools/build/verify_ensurepip_wheels.py'
1010
pull_request:
1111
paths:
1212
- 'Lib/ensurepip/_bundled/**'
1313
- '.github/workflows/verify-ensurepip-wheels.yml'
14-
- 'Tools/scripts/verify_ensurepip_wheels.py'
14+
- 'Tools/build/verify_ensurepip_wheels.py'
1515

1616
permissions:
1717
contents: read
@@ -29,4 +29,4 @@ jobs:
2929
with:
3030
python-version: '3'
3131
- name: Compare checksums of bundled pip and setuptools to ones published on PyPI
32-
run: ./Tools/scripts/verify_ensurepip_wheels.py
32+
run: ./Tools/build/verify_ensurepip_wheels.py

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ Tools/ssl/win32
143143
Tools/freeze/test/outdir
144144

145145
# The frozen modules are always generated by the build so we don't
146-
# keep them in the repo. Also see Tools/scripts/freeze_modules.py.
146+
# keep them in the repo. Also see Tools/build/freeze_modules.py.
147147
Python/frozen_modules/*.h
148148
# The manifest can be generated at any time with "make regen-frozen".
149149
Python/frozen_modules/MANIFEST

Doc/c-api/refcounting.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,26 @@ The macros in this section are used for managing reference counts of Python
1111
objects.
1212

1313

14+
.. c:function:: Py_ssize_t Py_REFCNT(PyObject *o)
15+
16+
Get the reference count of the Python object *o*.
17+
18+
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
19+
20+
.. versionchanged:: 3.11
21+
The parameter type is no longer :c:expr:`const PyObject*`.
22+
23+
.. versionchanged:: 3.10
24+
:c:func:`Py_REFCNT()` is changed to the inline static function.
25+
26+
27+
.. c:function:: void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt)
28+
29+
Set the object *o* reference counter to *refcnt*.
30+
31+
.. versionadded:: 3.9
32+
33+
1434
.. c:function:: void Py_INCREF(PyObject *o)
1535
1636
Increment the reference count for object *o*.

Doc/c-api/structures.rst

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ All Python objects ultimately share a small number of fields at the beginning
1717
of the object's representation in memory. These are represented by the
1818
:c:type:`PyObject` and :c:type:`PyVarObject` types, which are defined, in turn,
1919
by the expansions of some macros also used, whether directly or indirectly, in
20-
the definition of all other Python objects.
20+
the definition of all other Python objects. Additional macros can be found
21+
under :ref:`reference counting <countingrefs>`.
2122

2223

2324
.. c:type:: PyObject
@@ -121,26 +122,6 @@ the definition of all other Python objects.
121122
.. versionadded:: 3.9
122123
123124
124-
.. c:function:: Py_ssize_t Py_REFCNT(PyObject *o)
125-
126-
Get the reference count of the Python object *o*.
127-
128-
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
129-
130-
.. versionchanged:: 3.11
131-
The parameter type is no longer :c:expr:`const PyObject*`.
132-
133-
.. versionchanged:: 3.10
134-
:c:func:`Py_REFCNT()` is changed to the inline static function.
135-
136-
137-
.. c:function:: void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt)
138-
139-
Set the object *o* reference counter to *refcnt*.
140-
141-
.. versionadded:: 3.9
142-
143-
144125
.. c:function:: Py_ssize_t Py_SIZE(PyVarObject *o)
145126
146127
Get the size of the Python object *o*.

Doc/howto/logging-cookbook.rst

Lines changed: 206 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,211 @@ choose a different directory name for the log - just ensure that the directory e
276276
and that you have the permissions to create and update files in it.
277277

278278

279+
.. _custom-level-handling:
280+
281+
Custom handling of levels
282+
-------------------------
283+
284+
Sometimes, you might want to do something slightly different from the standard
285+
handling of levels in handlers, where all levels above a threshold get
286+
processed by a handler. To do this, you need to use filters. Let's look at a
287+
scenario where you want to arrange things as follows:
288+
289+
* Send messages of severity ``INFO`` and ``WARNING`` to ``sys.stdout``
290+
* Send messages of severity ``ERROR`` and above to ``sys.stderr``
291+
* Send messages of severity ``DEBUG`` and above to file ``app.log``
292+
293+
Suppose you configure logging with the following JSON:
294+
295+
.. code-block:: json
296+
297+
{
298+
"version": 1,
299+
"disable_existing_loggers": false,
300+
"formatters": {
301+
"simple": {
302+
"format": "%(levelname)-8s - %(message)s"
303+
}
304+
},
305+
"handlers": {
306+
"stdout": {
307+
"class": "logging.StreamHandler",
308+
"level": "INFO",
309+
"formatter": "simple",
310+
"stream": "ext://sys.stdout",
311+
},
312+
"stderr": {
313+
"class": "logging.StreamHandler",
314+
"level": "ERROR",
315+
"formatter": "simple",
316+
"stream": "ext://sys.stderr"
317+
},
318+
"file": {
319+
"class": "logging.FileHandler",
320+
"formatter": "simple",
321+
"filename": "app.log",
322+
"mode": "w"
323+
}
324+
},
325+
"root": {
326+
"level": "DEBUG",
327+
"handlers": [
328+
"stderr",
329+
"stdout",
330+
"file"
331+
]
332+
}
333+
}
334+
335+
This configuration does *almost* what we want, except that ``sys.stdout`` would
336+
show messages of severity ``ERROR`` and above as well as ``INFO`` and
337+
``WARNING`` messages. To prevent this, we can set up a filter which excludes
338+
those messages and add it to the relevant handler. This can be configured by
339+
adding a ``filters`` section parallel to ``formatters`` and ``handlers``:
340+
341+
.. code-block:: json
342+
343+
"filters": {
344+
"warnings_and_below": {
345+
"()" : "__main__.filter_maker",
346+
"level": "WARNING"
347+
}
348+
}
349+
350+
and changing the section on the ``stdout`` handler to add it:
351+
352+
.. code-block:: json
353+
354+
"stdout": {
355+
"class": "logging.StreamHandler",
356+
"level": "INFO",
357+
"formatter": "simple",
358+
"stream": "ext://sys.stdout",
359+
"filters": ["warnings_and_below"]
360+
}
361+
362+
A filter is just a function, so we can define the ``filter_maker`` (a factory
363+
function) as follows:
364+
365+
.. code-block:: python
366+
367+
def filter_maker(level):
368+
level = getattr(logging, level)
369+
370+
def filter(record):
371+
return record.levelno <= level
372+
373+
return filter
374+
375+
This converts the string argument passed in to a numeric level, and returns a
376+
function which only returns ``True`` if the level of the passed in record is
377+
at or below the specified level. Note that in this example I have defined the
378+
``filter_maker`` in a test script ``main.py`` that I run from the command line,
379+
so its module will be ``__main__`` - hence the ``__main__.filter_maker`` in the
380+
filter configuration. You will need to change that if you define it in a
381+
different module.
382+
383+
With the filter added, we can run ``main.py``, which in full is:
384+
385+
.. code-block:: python
386+
387+
import json
388+
import logging
389+
import logging.config
390+
391+
CONFIG = '''
392+
{
393+
"version": 1,
394+
"disable_existing_loggers": false,
395+
"formatters": {
396+
"simple": {
397+
"format": "%(levelname)-8s - %(message)s"
398+
}
399+
},
400+
"filters": {
401+
"warnings_and_below": {
402+
"()" : "__main__.filter_maker",
403+
"level": "WARNING"
404+
}
405+
},
406+
"handlers": {
407+
"stdout": {
408+
"class": "logging.StreamHandler",
409+
"level": "INFO",
410+
"formatter": "simple",
411+
"stream": "ext://sys.stdout",
412+
"filters": ["warnings_and_below"]
413+
},
414+
"stderr": {
415+
"class": "logging.StreamHandler",
416+
"level": "ERROR",
417+
"formatter": "simple",
418+
"stream": "ext://sys.stderr"
419+
},
420+
"file": {
421+
"class": "logging.FileHandler",
422+
"formatter": "simple",
423+
"filename": "app.log",
424+
"mode": "w"
425+
}
426+
},
427+
"root": {
428+
"level": "DEBUG",
429+
"handlers": [
430+
"stderr",
431+
"stdout",
432+
"file"
433+
]
434+
}
435+
}
436+
'''
437+
438+
def filter_maker(level):
439+
level = getattr(logging, level)
440+
441+
def filter(record):
442+
return record.levelno <= level
443+
444+
return filter
445+
446+
logging.config.dictConfig(json.loads(CONFIG))
447+
logging.debug('A DEBUG message')
448+
logging.info('An INFO message')
449+
logging.warning('A WARNING message')
450+
logging.error('An ERROR message')
451+
logging.critical('A CRITICAL message')
452+
453+
And after running it like this:
454+
455+
.. code-block:: shell
456+
457+
python main.py 2>stderr.log >stdout.log
458+
459+
We can see the results are as expected:
460+
461+
.. code-block:: shell
462+
463+
$ more *.log
464+
::::::::::::::
465+
app.log
466+
::::::::::::::
467+
DEBUG - A DEBUG message
468+
INFO - An INFO message
469+
WARNING - A WARNING message
470+
ERROR - An ERROR message
471+
CRITICAL - A CRITICAL message
472+
::::::::::::::
473+
stderr.log
474+
::::::::::::::
475+
ERROR - An ERROR message
476+
CRITICAL - A CRITICAL message
477+
::::::::::::::
478+
stdout.log
479+
::::::::::::::
480+
INFO - An INFO message
481+
WARNING - A WARNING message
482+
483+
279484
Configuration server example
280485
----------------------------
281486

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

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

3520-
35213725
Opening the same log file multiple times
35223726
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35233727

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

3569-
35703773
Adding handlers other than :class:`NullHandler` to a logger in a library
35713774
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35723775

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

3578-
35793781
Creating a lot of loggers
35803782
^^^^^^^^^^^^^^^^^^^^^^^^^
35813783

0 commit comments

Comments
 (0)